ifw-daq  2.1.0-pre1
IFW Data Acquisition modules
configManager.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @ingroup daq_dpm
4  * @copyright (c) Copyright ESO 2022
5  * All Rights Reserved
6  * ESO (eso.org) is an Intergovernmental Organisation, and therefore special legal conditions apply.
7  *
8  * @brief DPM server config
9  */
10 #include <configManager.hpp>
11 
12 #include <iostream>
13 #include <stdexcept>
14 
15 #include <boost/program_options.hpp>
16 #include <fmt/format.h>
17 #include <fmt/ostream.h>
18 #include <rad/helper.hpp>
19 #include <yaml-cpp/yaml.h>
20 
21 #include <daq/log4cplus.hpp>
22 
23 namespace daq::dpm {
24 
25 ConfigManager::ConfigManager(log4cplus::Logger logger)
26  : m_logger(std::move(logger)), m_mgr(&m_config, m_logger) {
27  m_mgr.Register(&Configuration::name, {"process-name", "Component instance ID"});
28  m_mgr.Register(&Configuration::dataroot, {"dataroot", "ICS standard DATAROOT directory"});
29  m_mgr.Register(&Configuration::workspace, {"workspace", "DPM merge workspace"});
30  m_mgr.Register(&Configuration::rr_uri, {"rr-uri", "Request/reply URI"});
31  m_mgr.Register(&Configuration::ps_uri, {"ps-uri", "Publish/subscribe URI"});
32  m_mgr.Register(&Configuration::no_ipc, {"no-ipc", "Disables IPC interfaces"});
33  m_mgr.Register(&Configuration::db_endpoint, {"db-endpoint", "REDIS 'host:port'"});
34  m_mgr.Register(&Configuration::db_timeout, {"db-timeout", "Database timeout"});
35  m_mgr.Register(&Configuration::log_level, {"log-level", "Log verbosity level"});
36  m_mgr.Register(&Configuration::log_config, {"log-config", "Log configuration file"});
37  m_mgr.Register(&Configuration::config_file, {"config-file", "YAML configuration file path"});
38  m_mgr.Register(&Configuration::poll_once, {"poll-once", "Poll scheduler once"});
39 
40  m_mgr.Register(&Configuration::merge_bin, {"merge-bin", "DPM Merge application binary."});
41  m_mgr.Register(&Configuration::rsync_bin, {"rsync-bin", "rsync application binary."});
42 
43  m_mgr.Register(&Configuration::limit_daq, {"limit-daq", "Concurrency limit: Number of DAQs"});
44  m_mgr.Register(&Configuration::limit_merge,
45  {"limit-merge", "Concurrency limit: Number of merges"});
46  m_mgr.Register(&Configuration::limit_net_send,
47  {"limit-net-send", "Concurrency limit: Number of network send tranfers."});
48  m_mgr.Register(
50  {"limit-net-receive", "Concurrency limit: Number of network receive transfers."});
51 
52  std::string db_addr = rad::Helper::GetEnvVar("DB_HOST");
53  if (auto root = rad::Helper::GetEnvVar("DATAROOT"); !root.empty()) {
54  m_mgr.Update(
55  &Configuration::dataroot, root, {config::Origin::EnvironmentVariable, "$DATAROOT"});
56  }
57 }
58 
59 bool ConfigManager::ParseArguments(int argc, char* argv[]) {
60  namespace po = boost::program_options;
61  try {
62  config::OriginInfo si{config::Origin::CommandLine, ""};
63  po::options_description options_desc("Options");
64  // clang-format off
65  // Note be careful of providing default_value as it will be interpreted as if user provided
66  // option!
67  options_desc.add_options()
68  ("help,h", "Print help messages")
69  ("proc-name,n",
70  po::value<std::string>(),
71  "Process name")
72  ("log-level,l",
73  po::value<std::string>(),
74  "Log level: ERROR, WARNING, STATE, EVENT, ACTION, INFO, DEBUG, TRACE")
75  ("config,c",
76  po::value<std::string>(),
77  "Configuration filename")
78  ("db-host,d",
79  po::value<std::string>(),
80  "In-memory DB host (ipaddr:port)")
81  ("rr-uri",
82  po::value<std::string>(),
83  "Request/reply URI")
84  ("ps-uri",
85  po::value<std::string>(),
86  "Publish/subscribe URI")
87  ("workspace",
88  po::value<std::string>(),
89  "workspace path (relative paths are relateive to dataroot)")
90  ("no-ipc",
91  "Disable request/reply, publish/subscribe and OLDB interfaces for standalone mode")
92  ("poll-once",
93  "Poll scheduler once and then exit rather than running until asked to quit (this "
94  "option also implies --no-ipc)")
95  ;
96  // clang-format on
97  po::variables_map options_map;
98  po::store(po::parse_command_line(argc, argv, options_desc), options_map);
99  if (options_map.count("help")) {
100  std::cerr << options_desc << std::endl;
101  return false;
102  }
103  po::notify(options_map);
104 
105  if (options_map.count("config")) {
106  auto value = options_map["config"].as<std::string>();
107  m_mgr.Update(&Configuration::config_file, value, si);
108  }
109 
110  if (options_map.count("log-level")) {
111  // Note we cannot use log4cplus::LogLevel as it's an alias to int and we want to parse
112  // a string using ostream, so we use the daq helper daq::LogLevel instead.
113  auto ll_str = options_map["log-level"].as<std::string>();
114  auto ll = boost::lexical_cast<LogLevel>(ll_str);
115  m_mgr.Update(&Configuration::log_level, ll.value, si);
116  }
117 
118  if (options_map.count("proc-name")) {
119  auto value = options_map["proc-name"].as<std::string>();
120  m_mgr.Update(&Configuration::name, value, si);
121  }
122 
123  if (options_map.count("db-host")) {
124  auto value = options_map["db-host"].as<std::string>();
125  m_mgr.Update(&Configuration::db_endpoint, value, si);
126  }
127  if (options_map.count("rr-uri")) {
128  auto value = options_map["rr-uri"].as<std::string>();
129  m_mgr.Update(&Configuration::rr_uri, value, si);
130  }
131  if (options_map.count("ps-uri")) {
132  auto value = options_map["ps-uri"].as<std::string>();
133  m_mgr.Update(&Configuration::ps_uri, value, si);
134  }
135  if (options_map.count("workspace")) {
136  auto value = options_map["workspace"].as<std::string>();
137  m_mgr.Update(&Configuration::workspace, value, si);
138  }
139  if (options_map.count("no-ipc")) {
140  m_mgr.Update(&Configuration::no_ipc, true, si);
141  }
142  if (options_map.count("poll-once")) {
143  m_mgr.Update(&Configuration::poll_once, true, si);
144  m_mgr.Update(
146  true,
147  {config::Origin::CommandLine, "Option is implicitly set due to `--poll-once`"});
148  }
149 
150  } catch (...) {
151  std::throw_with_nested(std::runtime_error("Failed to parse command line arguments"));
152  }
153  return true;
154 }
155 
157  std::string resolved = rad::Helper::FindFile(m_config.config_file);
158  LOG4CPLUS_INFO(m_logger, "Loading configuration from " << resolved);
159  if (resolved.empty()) {
160  auto msg = fmt::format("Could not resolve config file {}", m_config.config_file);
161  LOG4CPLUS_ERROR(m_logger, msg);
162  throw std::invalid_argument(msg);
163  }
164  config::OriginInfo si{config::Origin::Configuration, resolved};
165  auto config = YAML::LoadFile(resolved);
166 
167  if (auto const& node = config["cfg.dataroot"]; node) {
168  m_mgr.Update(&Configuration::dataroot, node.as<std::string>(), si);
169  }
170  if (auto const& node = config["cfg.workspace"]; node) {
171  m_mgr.Update(&Configuration::workspace, node.as<std::string>(), si);
172  }
173  if (auto const& node = config["cfg.log.properties"]; node) {
174  m_mgr.Update(&Configuration::log_config, node.as<std::string>(), si);
175  }
176  if (auto const& node = config["cfg.req.endpoint"]; node) {
177  m_mgr.Update(&Configuration::rr_uri, node.as<std::string>(), si);
178  }
179  if (auto const& node = config["cfg.pub.endpoint"]; node) {
180  m_mgr.Update(&Configuration::ps_uri, node.as<std::string>(), si);
181  }
182  if (auto const& node = config["cfg.bin.merge"]; node) {
183  m_mgr.Update(&Configuration::merge_bin, node.as<std::string>(), si);
184  }
185  if (auto const& node = config["cfg.bin.rsync"]; node) {
186  m_mgr.Update(&Configuration::rsync_bin, node.as<std::string>(), si);
187  }
188 
189  // Concurrency limits
190  if (auto const& node = config["cfg.limit.daq"]; node) {
191  m_mgr.Update(&Configuration::limit_daq, node.as<unsigned>(), si);
192  }
193  if (auto const& node = config["cfg.limit.merge"]; node) {
194  m_mgr.Update(&Configuration::limit_merge, node.as<unsigned>(), si);
195  }
196  if (auto const& node = config["cfg.limit.net.receive"]; node) {
197  m_mgr.Update(&Configuration::limit_net_receive, node.as<unsigned>(), si);
198  }
199  if (auto const& node = config["cfg.limit.net.send"]; node) {
200  m_mgr.Update(&Configuration::limit_net_send, node.as<unsigned>(), si);
201  }
202 
203 } catch (...) {
204  std::throw_with_nested(std::runtime_error(
205  fmt::format("Failed to load configuration from {}", m_config.config_file)));
206 }
207 
208 } // namespace daq::dpm
daq::dpm::Configuration::limit_net_send
uint16_t limit_net_send
Definition: config.hpp:92
daq::config::OriginInfo
Mutable metadata about a configuration attribute that describes where a value comes from.
Definition: manager.hpp:72
daq::dpm::Configuration::config_file
std::filesystem::path config_file
Configuration file.
Definition: config.hpp:83
daq::dpm::ConfigManager::ParseArguments
bool ParseArguments(int argc, char *argv[])
Parse configuration from command line arguments.
Definition: configManager.cpp:59
daq::dpm::Configuration::ps_uri
std::string ps_uri
Pub/sub URI.
Definition: config.hpp:53
daq::dpm::Configuration::db_timeout
std::chrono::seconds db_timeout
Definition: config.hpp:61
configManager.hpp
DPM server config.
daq::dpm::Configuration::merge_bin
std::string merge_bin
Merge application name.
Definition: config.hpp:71
daq::dpm::ConfigManager::LoadConfig
void LoadConfig()
Load configuration file and update configuration.
Definition: configManager.cpp:156
log4cplus.hpp
Declaration of log4cplus helpers.
daq::dpm::Configuration::rsync_bin
std::string rsync_bin
rsync application name.
Definition: config.hpp:76
daq::dpm::Configuration::name
std::string name
Process instance name.
Definition: config.hpp:31
daq::dpm::Configuration::log_config
std::string log_config
Log file, defaults to nothing.
Definition: config.hpp:66
daq::dpm::Configuration::db_endpoint
std::string db_endpoint
Definition: config.hpp:60
daq::dpm::Configuration::limit_merge
uint16_t limit_merge
Definition: config.hpp:91
daq::dpm::Configuration::no_ipc
bool no_ipc
If true (set by command line option only) it disables MAL service registration.
Definition: config.hpp:58
daq::dpm
Definition: testDpSpec.cpp:16
daq::dpm::Configuration::limit_net_receive
uint16_t limit_net_receive
Definition: config.hpp:93
daq::dpm::Configuration::workspace
std::filesystem::path workspace
Workspace.
Definition: config.hpp:43
daq::dpm::Configuration::log_level
log4cplus::LogLevel log_level
Definition: config.hpp:62
daq::dpm::ConfigManager::ConfigManager
ConfigManager(log4cplus::Logger logger)
Definition: configManager.cpp:25
daq::dpm::Configuration::dataroot
std::filesystem::path dataroot
Dataroot, normally this should be configured from environment variable $DATAROOT.
Definition: config.hpp:36
daq::dpm::Configuration::rr_uri
std::string rr_uri
Request/reply URI.
Definition: config.hpp:48
daq::dpm::Configuration::poll_once
bool poll_once
Run scheduler once.
Definition: config.hpp:88
daq::dpm::Configuration::limit_daq
uint16_t limit_daq
Definition: config.hpp:90