Belle II Software development
basf2.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9/*
10 * There are two ways to work with the framework. Either
11 * by executing "basf2" and providing a python steering
12 * file as an argument or by using the framework within
13 * python itself.
14 *
15 * This file implements the main executable "basf2".
16 */
17
18#include <Python.h> //Has to be the first include (restriction due to python)
19
20#include <framework/core/Environment.h>
21#include <framework/core/DataFlowVisualization.h>
22#include <framework/core/MetadataService.h>
23#include <framework/core/RandomNumbers.h>
24#include <framework/logging/Logger.h>
25#include <framework/logging/LogConfig.h>
26#include <framework/logging/LogSystem.h>
27#include <framework/utilities/FileSystem.h>
28
29
30#include <boost/program_options.hpp>
31#include <boost/algorithm/string/predicate.hpp> //for iequals()
32
33#include <cstdlib>
34#include <iostream>
35#include <string>
36#include <vector>
37#include <fstream>
38#include <locale>
39#include <codecvt>
40#include <filesystem>
41
42#ifdef HAS_CALLGRIND
43#include <valgrind/valgrind.h>
44#endif
45
46using namespace std;
47using namespace Belle2;
48
49namespace prog = boost::program_options;
50
51namespace {
52
53 void checkPythonStatus(PyConfig& config, PyStatus& status)
54 {
55 if (PyStatus_Exception(status)) {
56 PyConfig_Clear(&config);
57 Py_ExitStatusException(status);
58 }
59 }
60}
61
62int main(int argc, char* argv[])
63{
64 //Initialize metadata service
66
67 //Check for Belle2 environment variables (during environment initialisation)
69
70 //Get the lib path (checked for NULL in Environment)
71 const char* belle2SubDir = getenv("BELLE2_SUBDIR");
72 std::filesystem::path libPath = "lib";
73 libPath /= belle2SubDir;
74
75 string runModuleIOVisualization(""); //nothing done if empty
76 vector<string> arguments;
77 string pythonFile;
78
79 try {
80 //---------------------------------------------------
81 // Handle command line options
82 //---------------------------------------------------
83
84 prog::options_description generic("Generic options (to be used instead of steering file)");
85 generic.add_options()
86 ("help,h", "Print this help")
87 ("version,v", "Print long and verbose version string")
88 ("version-short", "Print short version string")
89 ("info", "Print information about basf2")
90 ("license", "Print the short version of the basf2 license")
91 ("modules,m", prog::value<string>()->implicit_value(""),
92 "Print a list of all available modules (can be limited to a given package), or give detailed information on a specific module given as an argument (case sensitive).")
93 ;
94
95 prog::options_description config("Configuration");
96 config.add_options()
97 ("steering", prog::value<string>(), "The python steering file to run.")
98 ("arg", prog::value<vector<string> >(&arguments), "Additional arguments to be passed to the steering file")
99 ("log_level,l", prog::value<string>(),
100 "Set global log level (one of DEBUG, INFO, RESULT, WARNING, or ERROR). Takes precedence over set_log_level() in steering file.")
101 ("package_log_level", prog::value<vector<string> >(),
102 "Set package log level. Can be specified multiple times to use more than one package. (Examples: 'klm:INFO or cdc:DEBUG:10') ")
103 ("module_log_level", prog::value<vector<string> >(),
104 "Set module log level. Can be specified multiple times to use more than one package. (Examples: 'EventInfoSetter:INFO or CDCDigitizer:DEBUG:10') ")
105 ("random-seed", prog::value<string>(),
106 "Set the default initial seed for the random number generator. "
107 "This does not take precedence over calls to set_random_seed() in the steering file, but just changes the default. "
108 "If no seed is set via either of these mechanisms, the initial seed will be taken from the system's entropy pool.")
109 ("debug_level,d", prog::value<unsigned int>(), "Set default debug level. Also sets the log level to DEBUG.")
110 ("events,n", prog::value<unsigned int>(), "Override number of events for EventInfoSetter; otherwise set maximum number of events.")
111 ("run", prog::value<int>(), "Override run for EventInfoSetter, must be used with -n and --experiment")
112 ("experiment", prog::value<int>(), "Override experiment for EventInfoSetter, must be used with -n and --run")
113 ("skip-events", prog::value<unsigned int>(),
114 "Override skipNEvents for EventInfoSetter and RootInput. Skips this many events before starting.")
115 ("input,i", prog::value<vector<string> >(),
116 "Override name of input file for (Seq)RootInput. Can be specified multiple times to use more than one file. For RootInput, wildcards (as in *.root or [1-3].root) can be used, but need to be escaped with \\ or by quoting the argument to avoid expansion by the shell.")
117 ("sequence,S", prog::value<vector<string> >(),
118 "Override the number sequence (e.g. 23:42,101) defining the entries (starting from 0) which are processed by RootInput."
119 "Must be specified exactly once for each file to be opened."
120 "This means one sequence per input file AFTER wildcard expansion."
121 "The first event has the number 0.")
122 ("output,o", prog::value<string>(),
123 "Override name of output file for (Seq)RootOutput. In case multiple modules are present in the path, only the first will be affected.")
124 ("processes,p", prog::value<int>(), "Override number of worker processes (>=1 enables, 0 disables parallel processing)");
125
126 prog::options_description advanced("Advanced Options");
127 advanced.add_options()
128 ("module-io", prog::value<string>(),
129 "Create diagram of inputs and outputs for a single module, saved as ModuleName.dot. To create a PostScript file, use e.g. 'dot ModuleName.dot -Tps -o out.ps'.")
130 ("visualize-dataflow", "Generate data flow diagram (dataflow.dot) for the executed steering file.")
131 ("stats",
132 "Enable collection of statistics during event processing (fills table called via 'print(statistics)). Useful for debugging, but adds extra processing time.")
133 ("dry-run",
134 "Read steering file, but do not start any event processing when process(path) is called. Prints information on input/output files that would be used during normal execution.")
135 ("dump-path", prog::value<string>(),
136 "Read steering file, but do not actually start any event processing. The module path the steering file would execute is instead pickled (serialized) into the given file.")
137 ("execute-path", prog::value<string>(),
138 "Do not read any provided steering file, instead execute the pickled (serialized) path from the given file.")
139 ("zmq",
140 "Use ZMQ for multiprocessing instead of a RingBuffer. This has many implications and should only be used by experts.")
141 ("job-information", prog::value<string>(),
142 "Create json file with metadata of output files and basf2 execution status.")
143 ("realm", prog::value<string>(),
144 "Set the realm of the basf2 execution (online or production).")
145 ("secondary-input", prog::value<vector<string>>(),
146 "Override name of input file for the secondary RootInput module used for the event embedding. Can be specified multiple times to use more than one file. Wildcards (as in *.root or [1-3].root) can be used, but need to be escaped with \\ or by quoting the argument to avoid expansion by the shell.")
147#ifdef HAS_CALLGRIND
148 ("profile", prog::value<string>(),
149 "Name of a module to profile using callgrind. If more than one module of that name is registered only the first one will be profiled.")
150#endif
151 ;
152
153 prog::options_description cmdlineOptions;
154 cmdlineOptions.add(generic).add(config).add(advanced);
155
156 prog::positional_options_description posOptDesc;
157 posOptDesc.add("steering", 1);
158 posOptDesc.add("arg", -1);
159
160 prog::variables_map varMap;
161 prog::store(prog::command_line_parser(argc, argv).
162 options(cmdlineOptions).positional(posOptDesc).run(), varMap);
163 prog::notify(varMap);
164
165 //Check for non-steering file options
166 if (varMap.count("help")) {
167 cout << "Usage: " << argv[0] << " [OPTIONS] [STEERING_FILE] [-- [STEERING_FILE_OPTIONS]]\n";
168 cout << cmdlineOptions << endl;
169 return 0;
170 } else if (varMap.count("version")) {
171 pythonFile = "basf2/version.py";
172 } else if (varMap.count("version-short")) {
173 pythonFile = "basf2/version_short.py";
174 } else if (varMap.count("info")) {
175 pythonFile = "basf2_cli/print_info.py";
176 } else if (varMap.count("license")) {
177 pythonFile = "basf2_cli/print_license.py";
178 } else if (varMap.count("modules")) {
179 string modArgs = varMap["modules"].as<string>();
180 if (!modArgs.empty()) {
181 arguments.insert(arguments.begin(), modArgs);
182 }
183 // recent boost program_options will not consume extra tokens for
184 // implicit options. In this case the module/package name gets consumed
185 // in the steering file so we just use that.
186 if (varMap.count("steering")) {
187 arguments.insert(arguments.begin(), varMap["steering"].as<string>());
188 }
189 pythonFile = "basf2_cli/modules.py";
190 } else if (varMap.count("module-io")) {
191 runModuleIOVisualization = varMap["module-io"].as<string>();
192 pythonFile = "basf2/core.py"; //make module maps available, visualization will happen later
193 } else if (varMap.count("execute-path")) {
194 Environment::Instance().setPicklePath(varMap["execute-path"].as<string>());
195 pythonFile = "basf2_cli/execute_pickled_path.py";
196 } else if (varMap.count("steering")) {
197 // steering file not misused as module name, so print it's name :D
198 pythonFile = varMap["steering"].as<string>();
199 } else {
200 // launch an interactive python session.
201 pythonFile = "interactive.py";
202 }
203
204 if (!pythonFile.empty()) {
205 //Search in local or central lib/ if this isn't a direct path
206 if (!std::filesystem::exists(pythonFile)) {
207 std::string libFile = FileSystem::findFile((libPath / pythonFile).string(), true);
208 if (!libFile.empty())
209 pythonFile = libFile;
210 }
211 if (varMap.count("steering") and not varMap.count("modules")) {
212 B2INFO("Steering file: " << pythonFile);
213 }
214 }
215
216 // -p
217 // Do now so that we can override if profiling is requested
218 if (varMap.count("processes")) {
219 int nprocesses = varMap["processes"].as<int>();
220 if (nprocesses < 0) {
221 B2FATAL("Invalid number of processes!");
222 }
224 }
225
226 // --zmq
227 if (varMap.count("zmq")) {
229 }
230
231
232#ifdef HAS_CALLGRIND
233 if (varMap.count("profile")) {
234 string profileModule = varMap["profile"].as<string>();
235 //We want to profile a module so check if we are running under valgrind
236 if (!RUNNING_ON_VALGRIND) {
237 //Apparently not. Ok, let's call ourself using valgrind
238 cout << "Profiling requested, restarting using callgrind" << endl;
239
240 //Sadly calling processes in C++ is very annoying as we have to
241 //build a command line.
242 vector<char*> cmd;
243 //First we add all valgrind arguments.
244 const vector<string> valgrind_argv {
245 "valgrind", "--tool=callgrind", "--instr-atstart=no", "--trace-children=no",
246 "--callgrind-out-file=callgrind." + profileModule + ".%p",
247 };
248 //As execvp wants non-const char* pointers we have to copy the string contents.
249 cmd.reserve(valgrind_argv.size());
250 for (const auto& arg : valgrind_argv) { cmd.push_back(strdup(arg.c_str())); }
251 //And now we add our own arguments, including the program name.
252 for (int i = 0; i < argc; ++i) { cmd.push_back(argv[i]); }
253 //Finally, execvp wants a nullptr as last argument
254 cmd.push_back(nullptr);
255 //And call this thing. Execvp will not return if successful as the
256 //current process will be replaced so we do not need to care about what
257 //happens if successful
258 if (execvp(cmd[0], cmd.data()) == -1) {
259 int errsv = errno;
260 perror("Problem calling valgrind");
261 return errsv;
262 }
263 }
264 //Ok, running under valgrind, set module name we want to profile in
265 //environment.
267 //and make sure there is no multiprocessing when profiling
269 }
270#endif
271
272 // -n
273 if (varMap.count("events")) {
274 unsigned int nevents = varMap["events"].as<unsigned int>();
275 if (nevents == 0 or nevents == std::numeric_limits<unsigned int>::max()) {
276 B2FATAL("Invalid number of events (valid range: 1.." << std::numeric_limits<unsigned int>::max() - 1 << ")!");
277 }
279 }
280 // --run & --experiment
281 if (varMap.count("experiment") or varMap.count("run")) {
282 if (!varMap.count("events"))
283 B2FATAL("--experiment and --run must be used with --events/-n!");
284 if (!(varMap.count("run") and varMap.count("experiment")))
285 B2FATAL("Both --experiment and --run must be specified!");
286
287 int run = varMap["run"].as<int>();
288 int experiment = varMap["experiment"].as<int>();
289 B2ASSERT("run must be >= 0!", run >= 0);
290 B2ASSERT("experiment must be >= 0!", experiment >= 0);
292 }
293
294 // --skip-events
295 if (varMap.count("skip-events")) {
296 unsigned int skipevents = varMap["skip-events"].as<unsigned int>();
298 }
299
300 // -i
301 if (varMap.count("input")) {
302 const auto& names = varMap["input"].as<vector<string>>();
304 }
305
306 // -S
307 if (varMap.count("sequence")) {
308 const auto& sequences = varMap["sequence"].as<vector<string>>();
310 }
311
312 // -o
313 if (varMap.count("output")) {
314 std::string name = varMap["output"].as<string>();
316 }
317
318 // -l
319 if (varMap.count("log_level")) {
320 std::string levelParam = varMap["log_level"].as<string>();
321 int level = -1;
322 for (int i = LogConfig::c_Debug; i < LogConfig::c_Fatal; i++) {
323 std::string thisLevel = LogConfig::logLevelToString((LogConfig::ELogLevel)i);
324 if (boost::iequals(levelParam, thisLevel)) { //case-insensitive
325 level = i;
326 break;
327 }
328 }
329 if (level < 0) {
330 B2FATAL("Invalid log level! Needs to be one of DEBUG, INFO, RESULT, WARNING, or ERROR.");
331 }
332
333 //set log level
335 //and make sure it takes precedence over anything in the steering file
337 }
338
339 // --package_log_level
340 if (varMap.count("package_log_level")) {
341 const auto& packLogList = varMap["package_log_level"].as<vector<string>>();
342 const std::string delimiter = ":";
343 for (const std::string& packLog : packLogList) {
344 if (packLog.find(delimiter) == std::string::npos) {
345 B2FATAL("In --package_log_level input " << packLog << ", no colon detected. ");
346 break;
347 }
348 /* string parsing for packageName:LOGLEVEL or packageName:DEBUG:LEVEL*/
349 auto packageName = packLog.substr(0, packLog.find(delimiter));
350 std::string logName = packLog.substr(packLog.find(delimiter) + delimiter.length(), packLog.length());
351 int debugLevel = -1;
352 if ((logName.find("DEBUG") != std::string::npos) && logName.length() > 5) {
353 try {
354 debugLevel = std::stoi(logName.substr(logName.find(delimiter) + delimiter.length(), logName.length()));
355 } catch (std::exception& e) {
356 B2WARNING("In --package_log_level, issue parsing debugLevel. Still setting log level to DEBUG.");
357 }
358 logName = "DEBUG";
359 }
360
361 int level = -1;
362 /* determine log level for package */
363 for (int i = LogConfig::c_Debug; i < LogConfig::c_Fatal; i++) {
364 std::string thisLevel = LogConfig::logLevelToString((LogConfig::ELogLevel)i);
365 if (boost::iequals(logName, thisLevel)) { //case-insensitive
366 level = i;
367 break;
368 }
369 }
370 if (level < 0) {
371 B2FATAL("Invalid log level! Needs to be one of DEBUG, INFO, RESULT, WARNING, or ERROR.");
372 }
373 /* set package log level*/
374 if ((logName == "DEBUG") && (debugLevel >= 0)) {
375 LogSystem::Instance().getPackageLogConfig(packageName).setDebugLevel(debugLevel);
376 }
378
379 }
380 }
381
382 // --module_log_level
383 if (varMap.count("module_log_level")) {
384 const auto& moduleLogList = varMap["module_log_level"].as<vector<string>>();
385 const std::string delimiter = ":";
386 for (const std::string& moduleLog : moduleLogList) {
387 if (moduleLog.find(delimiter) == std::string::npos) {
388 B2FATAL("In --module_log_level input " << moduleLog << ", no colon detected. ");
389 break;
390 }
391 /* string parsing for packageName:LOGLEVEL or packageName:DEBUG:LEVEL*/
392 auto moduleName = moduleLog.substr(0, moduleLog.find(delimiter));
393 std::string moduleLogName = moduleLog.substr(moduleLog.find(delimiter) + delimiter.length(), moduleLog.length());
394 int moduleDebugLevel = -1;
395 if ((moduleLogName.find("DEBUG") != std::string::npos) && moduleLogName.length() > 5) {
396 try {
397 moduleDebugLevel = std::stoi(moduleLogName.substr(moduleLogName.find(delimiter) + delimiter.length(), moduleLogName.length()));
398 } catch (std::exception& e) {
399 B2WARNING("In --module_log_level, issue parsing debugLevel. Still setting log level to DEBUG.");
400 }
401 moduleLogName = "DEBUG";
402 }
403
404 int module_level = -1;
405 /* determine log level for module */
406 for (int i = LogConfig::c_Debug; i < LogConfig::c_Fatal; i++) {
407 std::string moduleThisLevel = LogConfig::logLevelToString((LogConfig::ELogLevel)i);
408 if (boost::iequals(moduleLogName, moduleThisLevel)) { //case-insensitive
409 module_level = i;
410 break;
411 }
412 }
413 if (module_level < 0) {
414 B2FATAL("Invalid log level! Needs to be one of DEBUG, INFO, RESULT, WARNING, or ERROR.");
415 }
416 /* set package log level*/
417 if ((moduleLogName == "DEBUG") && (moduleDebugLevel >= 0)) {
418 LogSystem::Instance().getModuleLogConfig(moduleName).setDebugLevel(moduleDebugLevel);
419 }
421
422 }
423 }
424
425 // -d
426 if (varMap.count("debug_level")) {
427 unsigned int level = varMap["debug_level"].as<unsigned int>();
430 }
431
432 if (varMap.count("visualize-dataflow")) {
434 if (Environment::Instance().getNumberProcesses() > 0) {
435 B2WARNING("--visualize-dataflow cannot be used with parallel processing, no graphs will be saved!");
436 }
437 }
438
439 if (varMap.count("stats")) {
441 }
442
443 if (varMap.count("dry-run")) {
445 }
446
447 if (varMap.count("dump-path")) {
448 Environment::Instance().setPicklePath(varMap["dump-path"].as<string>());
449 }
450
451 if (varMap.count("random-seed")) {
452 RandomNumbers::initialize(varMap["random-seed"].as<string>());
453 }
454
455 if (varMap.count("job-information")) {
456 string jobInfoFile = varMap["job-information"].as<string>();
458 B2INFO("Job information file: " << jobInfoFile);
459 }
460
461 if (varMap.count("realm")) {
462 std::string realmParam = varMap["realm"].as<string>();
463 int realm = -1;
464 for (int i = LogConfig::c_Online; i <= LogConfig::c_Production; i++) {
465 std::string thisRealm = LogConfig::logRealmToString((LogConfig::ELogRealm)i);
466 if (boost::iequals(realmParam, thisRealm)) { //case-insensitive
467 realm = i;
468 break;
469 }
470 }
471 if (realm < 0) {
472 B2FATAL("Invalid realm! Needs to be one of online or production.");
473 }
475 }
476
477 if (varMap.count("secondary-input")) {
478 const auto& names = varMap["secondary-input"].as<vector<string>>();
480 }
481
482 } catch (exception& e) {
483 cerr << "error: " << e.what() << endl;
484 return 1;
485 } catch (...) {
486 cerr << "Exception of unknown type!" << endl;
487 return 1;
488 }
489
490 //---------------------------------------------------
491 // If the python file is set, execute it
492 //---------------------------------------------------
493 PyStatus status;
494 PyConfig config;
495 PyConfig_InitPythonConfig(&config);
496 config.install_signal_handlers = 0;
497 config.safe_path = 0;
498
499 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
500
501 std::vector<wstring> pyArgvString(arguments.size() + 2);
502
503
504 pyArgvString[0] = L"python3"; //set the executable
505 pyArgvString[1] = converter.from_bytes(pythonFile);
506 for (size_t i = 0; i < arguments.size(); i++) {
507 pyArgvString[i + 2] = converter.from_bytes(arguments[i]);
508 }
509 std::vector<const wchar_t*> pyArgvArray(pyArgvString.size());
510 for (size_t i = 0; i < pyArgvString.size(); ++i) {
511 pyArgvArray[i] = pyArgvString[i].c_str();
512 }
513
514
515 //Pass python filename and additional arguments to python
516 status = PyConfig_SetArgv(&config, pyArgvArray.size(), const_cast<wchar_t**>(pyArgvArray.data()));
517 checkPythonStatus(config, status);
518
519 status = Py_InitializeFromConfig(&config);
520 checkPythonStatus(config, status);
521
522 auto fullPath = std::filesystem::absolute(std::filesystem::path(pythonFile));
523
524 if ((std::filesystem::is_directory(fullPath)) || !(std::filesystem::exists(fullPath))) {
525 B2FATAL("The given filename and/or path is not valid: " + pythonFile);
526 }
527
528 std::ifstream file(fullPath.string().c_str());
529 std::stringstream buffer;
530 buffer << file.rdbuf();
531 Environment::Instance().setSteering(buffer.str());
532 int pyReturnValue = Py_RunMain();
533
534 //Finish Python interpreter
535 PyConfig_Clear(&config);
536 Py_Finalize();
537
538 //basf2.py was loaded, now do module I/O visualization
539 if (!runModuleIOVisualization.empty()) {
541 }
542
543 //--dry-run: print gathered information
544 if (Environment::Instance().getDryRun()) {
546 }
547
548 //Report completion in json metadata
549 MetadataService::Instance().addBasf2Status("finished successfully");
551
552 return pyReturnValue;
553}
static void executeModuleAndCreateIOPlot(const std::string &module)
Create independent I/O graph for a single module (without requiring a steering file).
void setOutputFileOverride(const std::string &name)
Override output file name for modules.
void setProfileModuleName(const std::string &name)
Set the name of a module to be profiled.
void setSteering(const std::string &steering)
Sets the steering file content.
void setStats(bool stats)
Enable collection of statistics during event processing.
void setNumberEventsOverride(unsigned int nevents)
Override the number of events in run 1 for EventInfoSetter module.
Definition Environment.h:65
void setRealm(LogConfig::ELogRealm realm)
Set the basf2 execution realm.
void setRunExperimentOverride(int run, int experiment)
Override run and experiment for EventInfoSetter.
Definition Environment.h:80
void setNumberProcessesOverride(int nproc)
Override number of processes to run in parallel.
void setLogLevelOverride(int level)
Override global log level if != LogConfig::c_Default.
void printJobInformation() const
Print information on input/output files in current steering file, used by –dry-run.
void setEntrySequencesOverride(const std::vector< std::string > &sequences)
Override the number sequences (e.g.
Definition Environment.h:71
static Environment & Instance()
Static method to get a reference to the Environment instance.
void setSecondaryInputFilesOverride(const std::vector< std::string > &names)
Override secondary input file names for modules.
void setUseZMQ(bool useZMQ)
Set the flag if ZMQ should be used instead of the RingBuffer multiprocessing implementation.
void setPicklePath(const std::string &path)
Sets the path to the file where the pickled path is stored.
void setSkipEventsOverride(unsigned int skipEvents)
Set skipNEvents override.
Definition Environment.h:88
void setVisualizeDataFlow(bool on)
Whether to generate DOT files with data store inputs/outputs of each module.
void setInputFilesOverride(const std::vector< std::string > &names)
Override input file names for modules.
void setDryRun(bool dryRun)
Read steering file, but do not start any actually start any event processing.
static std::string findFile(const std::string &path, bool silent=false)
Search for given file or directory in local or central release directory, and return absolute path if...
void setDebugLevel(int debugLevel)
Configure the debug messaging level.
Definition LogConfig.h:98
static const char * logRealmToString(ELogRealm realm)
Converts a log realm type to a string.
Definition LogConfig.cc:49
ELogLevel
Definition of the supported log levels.
Definition LogConfig.h:26
@ c_Debug
Debug: for code development.
Definition LogConfig.h:26
@ c_Fatal
Fatal: for situations were the program execution can not be continued.
Definition LogConfig.h:31
ELogRealm
Definition of the supported execution realms.
Definition LogConfig.h:48
@ c_Online
Online data taking.
Definition LogConfig.h:49
@ c_Production
Data production jobs.
Definition LogConfig.h:50
void setLogLevel(ELogLevel logLevel)
Configure the log level.
Definition LogConfig.cc:25
static const char * logLevelToString(ELogLevel logLevelType)
Converts a log level type to a string.
Definition LogConfig.cc:42
LogConfig * getLogConfig()
Returns global log system configuration.
Definition LogSystem.h:78
LogConfig & getModuleLogConfig(const std::string &module)
Get the log configuration for the module with the given name.
Definition LogSystem.h:105
static LogSystem & Instance()
Static method to get a reference to the LogSystem instance.
Definition LogSystem.cc:28
LogConfig & getPackageLogConfig(const std::string &package)
Get the log configuration for the package with the given name.
Definition LogSystem.h:96
void addBasf2Status(const std::string &message="")
Add metadata of basf2 status.
void setJsonFileName(const std::string &fileName)
Set the name of the json metadata file.
static MetadataService & Instance()
Static method to get a reference to the MetadataService instance.
void finishBasf2(bool success=true)
Add metadata for basf2 completion.
static void initialize()
Initialize the random number generator with a unique random seed;.
Abstract base class for different kinds of events.
STL namespace.