ifw-daq 3.1.0
IFW Data Acquisition modules
Loading...
Searching...
No Matches
config.cpp
Go to the documentation of this file.
1/**
2 * @file
3 * @ingroup server
4 * @copyright ESO - European Southern Observatory
5 * @author
6 *
7 * @brief Config class source file.
8 */
9
10#include "config.hpp"
11
12#include <iostream>
13#include <optional>
14
15#include <rad/assert.hpp>
16#include <rad/config.hpp>
17#include <rad/exceptions.hpp>
18#include <rad/helper.hpp>
19
20#include <boost/program_options.hpp>
21#include <fmt/chrono.h>
22#include <fmt/format.h>
23
25
26#include "logger.hpp"
27
28namespace bpo = boost::program_options;
29
30template <>
31struct daq::config::Formatter<std::filesystem::path> {
32 static auto Format(std::filesystem::path const &t) {
33 return t.c_str();
34 }
35};
36
37namespace server {
38
40 : m_mgr(GetLogger())
41 , m_proc_name(CONFIG_DEFAULT_PROCNAME)
42 , m_log_level(CONFIG_DEFAULT_LOG_LEVEL)
43 , m_log_properties()
44 , m_config_filename(CONFIG_DEFAULT_FILENAME)
45 , m_scxml_filename(CONFIG_DEFAULT_SCXML_FILENAME)
46 , m_db_prefix(CONFIG_DEFAULT_OLDB_URI_PREFIX + "/ocm")
47 , m_db_timeout_sec(CONFIG_DEFAULT_DB_TIMEOUT_SEC)
48 , m_req_endpoint(CONFIG_DEFAULT_REQ_ENDPOINT)
49 , m_pub_endpoint(CONFIG_DEFAULT_PUB_ENDPOINT)
50 , m_out_path()
51 , m_workspace(CONFIG_DEFAULT_WORKSPACE) {
52 RAD_TRACE(GetLogger());
53 m_mgr.Register(&m_instrument_id, {"cfg/instrument_id", "Instrument id"});
54 m_mgr.Register(&m_proc_name, {rad::KEY_CONFIG_PROCNAME, "Component instance ID"});
55 m_mgr.Register(&m_log_level, {rad::KEY_CONFIG_LOG_LEVEL, "Log verbosity level"});
56 m_mgr.Register(&m_log_properties, {rad::KEY_CONFIG_LOG_PROPERTIES, "Log configuration file"});
57 m_mgr.Register(&m_config_filename, {rad::KEY_CONFIG_FILENAME, "YAML configuration file path"});
58
60 {rad::KEY_CONFIG_SM_SCXML, "State machine SCXML model file path"});
61 m_mgr.Register(&m_db_prefix, {rad::KEY_CONFIG_OLDB_URI_PREFIX, "CII OLDB URI prefix"});
63 {rad::KEY_CONFIG_OLDB_CONN_TIMEOUT, "CII OLDB timeout (sec)"});
64 m_mgr.Register(&m_out_path, {KEY_CONFIG_DATAROOT, "ICS standard DATAROOT directory"});
65 m_mgr.Register(&m_req_endpoint, {rad::KEY_CONFIG_REQ_ENDPOINT, "Request/reply URI"});
66 m_mgr.Register(&m_pub_endpoint, {"cfg/pub_endpoint", "Publish/subscribe URI"});
67 m_mgr.Register(&m_workspace, {"cfg/daq/workspace", "OCM DAQ workspace"});
68
69 m_mgr.Register(&m_dpm_params.rr_uri, {"cfg/dpm/req_endpoint", "DPM request/reply URI"});
70 m_mgr.Register(&m_dpm_params.ps_uri, {"cfg/dpm/pub_endpoint", "DPM publish/subscribe URI"});
71 m_mgr.Register(&m_dpm_params.timeout, {"cfg/dpm/timeout_sec", "DPM timeout (sec)"});
72
74 {"cfg/daq/stale_acquiring_hours",
75 "Age when DAQ acquisitions are considered stale (hours)"});
78 {"cfg/daq/stale_merging_hours", "Age when DAQ merges are considered stale (hours)"});
80 {"cfg/dictionaries", "Specifies the FITS keyword dictionaries to load"});
81
82 /*
83 * Read environment variables.
84 */
85 if (auto val = rad::Helper::GetEnvVar(CONFIG_ENVVAR_OUT_PATH); !val.empty()) {
87 }
88}
89
90bool Config::ParseOptions(int argc, char *argv[]) {
91 RAD_TRACE(GetLogger());
92
93 /*
94 * Define command line options.
95 */
96 bpo::options_description options_desc("Options");
97 // clang-format off
98 options_desc.add_options()
99 ("help,h", "Print help messages")
100 ("proc-name,n",
101 bpo::value<std::string>(),
102 "Process name")
103 ("log-level,l",
104 bpo::value<std::string>(),
105 "Log level: ERROR, WARNING, STATE, EVENT, ACTION, INFO, DEBUG, TRACE")
106 ("config,c",
107 bpo::value<std::string>(),
108 "Configuration filename")
109 ("db-host,d",
110 bpo::value<std::string>(),
111 "*deprecated* In-memory DB host (ipaddr:port)");
112 // clang-format on
113
114 // Parse the options.
115 try {
116 bpo::variables_map options_map;
117 bpo::store(bpo::parse_command_line(argc, argv, options_desc), options_map);
118 if (options_map.count("help")) {
119 std::cout << options_desc << std::endl;
120 return false;
121 }
122
123 /*
124 * Throws on error, so do after help in case
125 * there are any problems.
126 */
127 bpo::notify(options_map);
128
130
131 if (options_map.count("log-level")) {
132 // Note we cannot use log4cplus::LogLevel as it's an alias to int and we want to parse
133 // a string using ostream, so we use the daq helper daq::LogLevel instead.
134 auto ll_str = options_map["log-level"].as<std::string>();
135 m_mgr.Update(&m_log_level, ll_str, si);
136 }
137
138 if (options_map.count("proc-name")) {
139 auto value = options_map["proc-name"].as<std::string>();
140 if (m_mgr.Update(&m_proc_name, value, si)) {
141 // Since proc-name updated we also update default for db-prefix
145 }
146 }
147
148 if (options_map.count("config")) {
149 auto value = options_map["config"].as<std::string>();
150 m_mgr.Update(&m_config_filename, value, si);
151 }
152 if (options_map.count("db-host")) {
153 LOG4CPLUS_WARN(GetLogger(),
154 "Command line parameter --db-host|-d is deprecated and only provided "
155 "for compatibility");
156 }
157 } catch (bpo::error &e) {
158 std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
159 std::cerr << options_desc << std::endl;
160 throw std::invalid_argument(e.what());
161 }
162
163 return true;
164}
165
166void Config::LoadConfig(const std::string &filename) {
167 RAD_TRACE(GetLogger());
168 m_config.emplace();
169
170 std::string config_filename = filename;
171 if (config_filename == "") {
172 config_filename = m_config_filename;
173 }
174
175 // resolve filename
176 std::string resolved_config_filename = rad::Helper::FindFile(config_filename);
177 if (resolved_config_filename.size() == 0) {
178 LOG4CPLUS_ERROR(GetLogger(), "Cannot find <" << config_filename << ">");
179 char const *cfgpath = std::getenv("CFGPATH");
180 if (cfgpath == nullptr) {
181 cfgpath = "{unset}";
182 }
183 throw rad::Exception("Cannot find " + config_filename, fmt::format("$CFGPATH={}", cfgpath));
184 } else {
185 LOG4CPLUS_DEBUG(GetLogger(),
186 "Loading configuration from <" << resolved_config_filename << ">");
187 }
188 try {
190 auto ifs = std::ifstream(resolved_config_filename);
191 ifs.exceptions(std::ios_base::badbit);
192
193 m_config->UpdateFromStream(ifs);
194 auto const &root = m_config->GetInstanceRootNode();
196
197 if (auto value = GetParamAs<std::string>(rad::KEY_CONFIG_LOG_PROPERTIES, root); value) {
198 m_mgr.Update(&m_log_properties, *value, si);
199 }
200
201 if (auto value = GetParamAs<std::string>(rad::KEY_CONFIG_REQ_ENDPOINT, root); value) {
202 auto updated = m_mgr.Update(&m_req_endpoint, *value, si);
203 if (updated && m_req_endpoint.empty()) {
204 throw rad::Exception("Invalid configuration",
205 fmt::format("invalid configuration for '{}': '{}' request "
206 "endpoint must be non-empty and have a trailing "
207 "path separator '/'.",
208 rad::KEY_CONFIG_REQ_ENDPOINT,
210 }
211 }
212 if (auto value = GetParamAs<std::string>(KEY_CONFIG_PUB_ENDPOINT, root); value) {
213 auto updated = m_mgr.Update(&m_pub_endpoint, *value, si);
214 if (updated && m_pub_endpoint.empty()) {
215 throw rad::Exception("Invalid configuration",
216 fmt::format("invalid configuration for '{}': '{}' publish "
217 "endpoint must be non-empty and have a trailing "
218 "path separator '/'.",
221 }
222 }
223
224 if (auto value = GetParamAs<std::string>(rad::KEY_CONFIG_OLDB_URI_PREFIX, root); value) {
225 m_mgr.Update(&m_db_prefix, *value, si);
226 }
227
228 if (auto value = GetParamAs<int>(rad::KEY_CONFIG_OLDB_CONN_TIMEOUT, root); value) {
229 m_mgr.Update(&m_db_timeout_sec, *value, si);
230 }
231
232 if (auto value = GetParamAs<std::string>(rad::KEY_CONFIG_SM_SCXML, root); value) {
233 m_mgr.Update(&m_scxml_filename, *value, si);
234 }
235
236 if (auto value = GetParamAs<std::string>(KEY_CONFIG_INSTRUMENT_ID, root); value) {
237 m_mgr.Update(&m_instrument_id, *value, si);
238 } else {
239 LOG4CPLUS_ERROR(
240 GetLogger(),
241 "Required configuration parameter <" << KEY_CONFIG_INSTRUMENT_ID << "> missing");
242 throw rad::Exception(
243 "Invalid configuration: Required parameter empty: " + KEY_CONFIG_INSTRUMENT_ID,
244 filename);
245 }
246 if (auto value = GetParamAs<std::string>(KEY_CONFIG_DATAROOT, root); value) {
247 m_mgr.Update(&m_out_path, *value, si);
248 }
249 // Workspace
250 if (auto value = GetParamAs<std::string>(KEY_CONFIG_WORKSPACE, root); value) {
251 m_mgr.Update(&m_workspace, *value, si);
252 }
253 LOG4CPLUS_DEBUG(GetLogger(), "Resolved workspace = <" << GetWorkspace() << ">");
254 // Stale daqs from workspace
255 if (auto value = GetParamAs<int>(KEY_CONFIG_STALE_DAQ_ACQUIRING, root); value) {
256 m_mgr.Update(&m_stale_acquiring, std::chrono::hours(*value), si);
257 }
258 if (auto value = GetParamAs<int>(KEY_CONFIG_STALE_DAQ_MERGING, root)) {
259 m_mgr.Update(&m_stale_merging, std::chrono::hours(*value), si);
260 }
261 // DPM
262 if (auto value = GetParamAs<std::string>(KEY_CONFIG_DPM_REQ_ENDPOINT, root); value) {
263 m_mgr.Update(&m_dpm_params.rr_uri, *value, si);
264 } else {
265 LOG4CPLUS_ERROR(
266 GetLogger(),
267 "Required configuration parameter <" << KEY_CONFIG_DPM_REQ_ENDPOINT << "> missing");
268 throw rad::Exception(
269 "Invalid configuration: Required parameter empty: " + KEY_CONFIG_DPM_REQ_ENDPOINT,
270 filename);
271 }
272 if (auto value = GetParamAs<std::string>(KEY_CONFIG_DPM_PUB_ENDPOINT, root); value) {
273 m_mgr.Update(&m_dpm_params.ps_uri, *value, si);
274 } else {
275 LOG4CPLUS_ERROR(
276 GetLogger(),
277 "Required configuration parameter <" << KEY_CONFIG_DPM_PUB_ENDPOINT << "> missing");
278 throw rad::Exception(
279 "Invalid configuration: Required parameter empty: " + KEY_CONFIG_DPM_PUB_ENDPOINT,
280 filename);
281 }
282 if (auto value = GetParamAs<int>(KEY_CONFIG_DPM_TIMEOUT_SEC, root); value) {
283 m_mgr.Update(&m_dpm_params.timeout, std::chrono::seconds(*value), si);
284 }
285 if (auto value = GetParamAs<std::vector<std::string>>(KEY_CONFIG_DICTIONARIES, root);
286 value) {
287 m_mgr.Update(&m_dictionary_names, *value, si);
288 }
289 } catch (std::exception const &e) {
290 LOG4CPLUS_ERROR(GetLogger(), e.what());
291 throw rad::Exception("Failed to load configuration", filename);
292 }
293
294 LOG4CPLUS_DEBUG(GetLogger(), "Loaded configuration file <" << m_config_filename << ">");
295}
296
297const std::string &Config::GetMsgReplierEndpoint() const {
298 RAD_TRACE(GetLogger());
299 return m_req_endpoint;
300}
301
302const std::string &Config::GetPubEndpoint() const {
303 RAD_TRACE(GetLogger());
304 return m_pub_endpoint;
305}
306
307const std::string &Config::GetDbPrefix() const {
308 RAD_TRACE(GetLogger());
309 if (m_db_prefix.empty()) {
310 return m_proc_name;
311 } else {
312 return m_db_prefix;
313 }
314}
315
316std::chrono::seconds Config::GetDbTimeout() const {
317 return std::chrono::seconds(m_db_timeout_sec);
318}
319
320const std::string &Config::GetSmScxmlFilename() const {
321 RAD_TRACE(GetLogger());
322 return m_scxml_filename;
323}
324
325const std::string &Config::GetConfigFilename() const {
326 RAD_TRACE(GetLogger());
327 return m_config_filename;
328}
329
330const std::string &Config::GetProcName() const {
331 RAD_TRACE(GetLogger());
332 return m_proc_name;
333}
334
335const std::string &Config::GetLogLevel() const {
336 RAD_TRACE(GetLogger());
337 return m_log_level;
338}
339
340const std::string &Config::GetLogProperties() const {
341 RAD_TRACE(GetLogger());
342 return m_log_properties;
343}
344
345std::vector<std::string> const &Config::GetDictionaryNames() const {
346 return m_dictionary_names;
347}
348
350 return m_dpm_params;
351}
352
353} // namespace server
bool Update(AttrType *ptr, T const &value, OriginInfo const &origin)
Update configuration value taking into account the origin of the change.
Definition: manager.hpp:293
void Register(AttrType *ptr, Metadata const &meta)
Registers a configuration parameter/attribute.
Definition: manager.hpp:251
const std::string & GetLogLevel() const
Definition: config.cpp:335
std::filesystem::path GetWorkspace() const
Definition: config.hpp:151
std::string m_pub_endpoint
Definition: config.hpp:176
daq::DpmClientParams m_dpm_params
Definition: config.hpp:179
std::string m_out_path
Definition: config.hpp:177
const std::string & GetSmScxmlFilename() const
Definition: config.cpp:320
std::string m_log_properties
Definition: config.hpp:170
bool ParseOptions(int argc, char *argv[])
Disable assignment operator.
Definition: config.cpp:90
Config()
Default constructor.
Definition: config.cpp:39
daq::DpmClientParams const & GetDpmClientParams() const
Definition: config.cpp:349
const std::string & GetMsgReplierEndpoint() const
Definition: config.cpp:297
const std::string & GetConfigFilename() const
Definition: config.cpp:325
int m_db_timeout_sec
Definition: config.hpp:174
void LoadConfig(const std::string &filename="")
This method load from a configuration file the application configuration overriding the initializatio...
Definition: config.cpp:166
std::chrono::seconds GetDbTimeout() const
Definition: config.cpp:316
std::string m_proc_name
Definition: config.hpp:167
std::optional< elt::configng::CiiConfigDocument > m_config
Definition: config.hpp:165
std::chrono::hours m_stale_merging
Definition: config.hpp:181
std::string m_log_level
Definition: config.hpp:169
std::chrono::hours m_stale_acquiring
Definition: config.hpp:180
std::string m_instrument_id
Definition: config.hpp:168
const std::string & GetLogProperties() const
Definition: config.cpp:340
std::string m_req_endpoint
Definition: config.hpp:175
std::vector< std::string > m_dictionary_names
Definition: config.hpp:182
std::string m_config_filename
Definition: config.hpp:171
daq::config::Manager m_mgr
Definition: config.hpp:162
std::string m_db_prefix
Definition: config.hpp:173
std::filesystem::path m_workspace
Definition: config.hpp:178
const std::string & GetProcName() const
Definition: config.cpp:330
std::vector< std::string > const & GetDictionaryNames() const
Definition: config.cpp:345
const std::string & GetPubEndpoint() const
Definition: config.cpp:302
std::string m_scxml_filename
Definition: config.hpp:172
const std::string & GetDbPrefix() const
Definition: config.cpp:307
daq::config::Manager and associated types.
Default logger name.
@ Configuration
Configuration file.
@ Default
Built-in default value.
@ CommandLine
Command line argument.
@ EnvironmentVariable
Environment variable.
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:350
Mutable metadata about a configuration attribute that describes where a value comes from.
Definition: manager.hpp:129
std::chrono::seconds timeout
Definition: dpmClient.hpp:96
std::string rr_uri
Definition: dpmClient.hpp:94
std::string ps_uri
Definition: dpmClient.hpp:95
Connection parameters for DPM.
Definition: dpmClient.hpp:93
const std::string CONFIG_DEFAULT_WORKSPACE
Definition: config.hpp:43
const std::string KEY_CONFIG_PUB_ENDPOINT
Rad configuration keys.
Definition: config.hpp:26
const std::string KEY_CONFIG_DPM_TIMEOUT_SEC
Definition: config.hpp:36
const std::string KEY_CONFIG_STALE_DAQ_ACQUIRING
Definition: config.hpp:30
const std::string CONFIG_DEFAULT_SCXML_FILENAME
Definition: config.hpp:44
const std::string KEY_CONFIG_DATAROOT
Definition: config.hpp:28
const std::string KEY_CONFIG_DICTIONARIES
Definition: config.hpp:32
const std::string CONFIG_DEFAULT_REQ_ENDPOINT
Definition: config.hpp:47
const std::string CONFIG_DEFAULT_OLDB_URI_PREFIX
Definition: config.hpp:49
const std::string KEY_CONFIG_DPM_PUB_ENDPOINT
Definition: config.hpp:35
const std::string KEY_CONFIG_WORKSPACE
Definition: config.hpp:29
const int CONFIG_DEFAULT_DB_TIMEOUT_SEC
Definition: config.hpp:46
const std::string CONFIG_DEFAULT_PUB_ENDPOINT
Definition: config.hpp:48
const std::string CONFIG_DEFAULT_LOG_LEVEL
Definition: config.hpp:45
const std::string KEY_CONFIG_INSTRUMENT_ID
Definition: config.hpp:27
const std::string CONFIG_ENVVAR_OUT_PATH
Application configuration environment variables.
Definition: config.hpp:55
const std::string CONFIG_DEFAULT_PROCNAME
Default application configuration values.
Definition: config.hpp:41
const std::string CONFIG_DEFAULT_FILENAME
Definition: config.hpp:42
const std::string KEY_CONFIG_STALE_DAQ_MERGING
Definition: config.hpp:31
const std::string KEY_CONFIG_DPM_REQ_ENDPOINT
Definition: config.hpp:34
log4cplus::Logger & GetLogger()
Definition: logger.cpp:14
Config class header file.
static auto Format(std::filesystem::path const &t)
Definition: config.cpp:32
Extension point to allow adaptations from non-formattable configurations types.
Definition: manager.hpp:82