ifw-daq  3.0.0-pre2
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 <fstream>
13 #include <iostream>
14 #include <stdexcept>
15 
16 #include <boost/program_options.hpp>
17 #include <fmt/chrono.h>
18 #include <fmt/format.h>
19 #include <fmt/ostream.h>
20 #include <rad/helper.hpp>
21 
22 #include <daq/log4cplus.hpp>
23 
24 namespace daq::dpm {
25 
26 ConfigManager::ConfigManager(log4cplus::Logger logger)
27  : m_logger(std::move(logger)), m_mgr(m_logger) {
28  m_mgr.Register(&m_config.name, {"cfg/procname", "Component instance ID"});
29  m_mgr.Register(&m_config.dataroot, {"cfg/dataroot", "ICS standard DATAROOT directory"});
30  m_mgr.Register(&m_config.workspace, {"cfg/daq/workspace", "DPM merge workspace"});
31  m_mgr.Register(&m_config.rr_uri, {"cfg/req_endpoint", "Request/reply URI"});
32  m_mgr.Register(&m_config.ps_uri, {"cfg/pub_endpoint", "Publish/subscribe URI"});
33  m_mgr.Register(&m_config.no_ipc, {"cfg/no_ipc", "Disables IPC interfaces"});
34  m_mgr.Register(&m_config.db_prefix,
35  {"cfg/oldb_uri_prefix", "CII OLDB prefix 'cii.oldb:/elt/..'"});
36  m_mgr.Register(&m_config.db_timeout, {"cfg/oldb_conn_timeout", "CII OLDB connection timeout"});
37  m_mgr.Register(&m_config.log_level, {"cfg/log_level", "Log verbosity level"});
38  m_mgr.Register(&m_config.log_config, {"cfg/log_properties", "Log configuration file"});
39  m_mgr.Register(&m_config.config_file, {"cfg/filename", "YAML configuration file path"});
40  m_mgr.Register(&m_config.poll_once, {"cfg/poll_once", "Poll scheduler once"});
41 
42  m_mgr.Register(&m_config.merge_bin, {"cfg/bin_merge", "DPM Merge application binary."});
43  m_mgr.Register(&m_config.rsync_bin, {"cfg/bin_rsync", "rsync application binary."});
44 
45  m_mgr.Register(&m_config.limit_daq, {"cfg/limits/daq", "Concurrency limit: Number of DAQs"});
46  m_mgr.Register(&m_config.limit_merge,
47  {"cfg/limits/merge", "Concurrency limit: Number of merges"});
48  m_mgr.Register(&m_config.limit_net_send,
49  {"cfg/limits/net_send", "Concurrency limit: Number of network send tranfers."});
50  m_mgr.Register(
51  &m_config.limit_net_receive,
52  {"cfg/limits/net_receive", "Concurrency limit: Number of network receive transfers."});
53 
54  if (auto root = rad::Helper::GetEnvVar("DATAROOT"); !root.empty()) {
55  m_mgr.Update(&m_config.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 {
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(&m_config.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(&m_config.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  if (m_mgr.Update(&m_config.name, value, si)) {
121  // Since proc-name updated we also update default for db-prefix
122  m_mgr.Update(&m_config.db_prefix,
123  "cii.oldb:/elt/" + m_config.name,
124  {daq::config::Origin::Default, "Updated default using proc-name"});
125  }
126  }
127 
128  if (options_map.count("db-host")) {
129  LOG4CPLUS_WARN(m_logger,
130  "Command line parameter --db-host|-d is deprecated and only provided "
131  "for compatibility");
132  }
133  if (options_map.count("rr-uri")) {
134  auto value = options_map["rr-uri"].as<std::string>();
135  m_mgr.Update(&m_config.rr_uri, value, si);
136  }
137  if (options_map.count("ps-uri")) {
138  auto value = options_map["ps-uri"].as<std::string>();
139  m_mgr.Update(&m_config.ps_uri, value, si);
140  }
141  if (options_map.count("workspace")) {
142  auto value = options_map["workspace"].as<std::string>();
143  m_mgr.Update(&m_config.workspace, value, si);
144  }
145  if (options_map.count("no-ipc")) {
146  m_mgr.Update(&m_config.no_ipc, true, si);
147  }
148  if (options_map.count("poll-once")) {
149  m_mgr.Update(&m_config.poll_once, true, si);
150  m_mgr.Update(
151  &m_config.no_ipc,
152  true,
153  {config::Origin::CommandLine, "Option is implicitly set due to `--poll-once`"});
154  }
155 
156  } catch (...) {
157  std::throw_with_nested(std::runtime_error("Failed to parse command line arguments"));
158  }
159  return true;
160 }
161 
162 void ConfigManager::LoadConfig() try {
163  std::string resolved = rad::Helper::FindFile(m_config.config_file);
164  LOG4CPLUS_INFO(m_logger, "Loading configuration from " << resolved);
165  if (resolved.empty()) {
166  auto msg = fmt::format("Could not resolve config file {}", m_config.config_file);
167  LOG4CPLUS_ERROR(m_logger, msg);
168  throw std::invalid_argument(msg);
169  }
172  auto ifs = std::ifstream(resolved);
173  ifs.exceptions(std::ios_base::badbit);
174 
175  elt::configng::CiiConfigDocument config;
176  config.UpdateFromStream(ifs);
177  auto const& root = config.GetInstanceRootNode();
178 
180  UpdateFromConfig<std::string>(&m_config.dataroot, root, si);
181  UpdateFromConfig<std::string>(&m_config.workspace, root, si);
182  UpdateFromConfig<std::string>(&m_config.log_config, root, si);
183  UpdateFromConfig<std::string>(&m_config.rr_uri, root, si);
184  UpdateFromConfig<std::string>(&m_config.ps_uri, root, si);
185  UpdateFromConfig<std::string>(&m_config.merge_bin, root, si);
186  UpdateFromConfig<std::string>(&m_config.rsync_bin, root, si);
187  // OLDB
188  UpdateFromConfig<std::string>(&m_config.db_prefix, root, si);
189  UpdateFromConfig<int>(&m_config.db_timeout, root, si);
190  // Concurrency limits
191  UpdateFromConfig<int>(&m_config.limit_daq, root, si);
192  UpdateFromConfig<int>(&m_config.limit_merge, root, si);
193  UpdateFromConfig<int>(&m_config.limit_net_receive, root, si);
194  UpdateFromConfig<int>(&m_config.limit_net_send, root, si);
195 
196 } catch (...) {
197  std::throw_with_nested(std::runtime_error(
198  fmt::format("Failed to load configuration from {}", m_config.config_file)));
199 }
200 
201 } // namespace daq::dpm
bool Update(AttrType *ptr, T const &value, OriginInfo const &origin)
Update configuration value taking into account the origin of the change.
Definition: manager.hpp:280
void Register(AttrType *ptr, Metadata const &meta)
Registers a configuration parameter/attribute.
Definition: manager.hpp:238
ConfigManager(log4cplus::Logger logger)
bool ParseArguments(int argc, char *argv[])
Parse configuration from command line arguments.
DPM server config.
Declaration of log4cplus helpers.
@ Configuration
Configuration file.
@ Default
Built-in default value.
@ CommandLine
Command line argument.
std::optional< T > GetParamAs(std::string const &query, elt::configng::CiiConfigInstanceNode const &node)
Performs lookup of parameters in the form root/node/leaf relative to the provided node.
Definition: manager.hpp:337
Mutable metadata about a configuration attribute that describes where a value comes from.
Definition: manager.hpp:116
std::string name
Process instance name.
Definition: config.hpp:37
log4cplus::LogLevel log_level
Definition: config.hpp:68
std::string rsync_bin
rsync application name.
Definition: config.hpp:82
std::filesystem::path dataroot
Dataroot, normally this should be configured from environment variable $DATAROOT.
Definition: config.hpp:42
std::string merge_bin
Merge application name.
Definition: config.hpp:77
std::filesystem::path workspace
Workspace.
Definition: config.hpp:49
std::chrono::seconds db_timeout
Definition: config.hpp:67
bool no_ipc
If true (set by command line option only) it disables MAL service registration.
Definition: config.hpp:64
std::string rr_uri
Request/reply URI.
Definition: config.hpp:54
std::string ps_uri
Pub/sub URI.
Definition: config.hpp:59
std::string db_prefix
Definition: config.hpp:66
std::string log_config
Log file, defaults to nothing.
Definition: config.hpp:72
bool poll_once
Run scheduler once.
Definition: config.hpp:94
uint16_t limit_net_send
Definition: config.hpp:98
std::filesystem::path config_file
Configuration file.
Definition: config.hpp:89
uint16_t limit_net_receive
Definition: config.hpp:99