Single Logger implementation for FairLogger & FairMQLogger

This commit is contained in:
Alexey Rybalchenko
2017-10-11 15:49:49 +02:00
committed by Mohammad Al-Turany
parent d3e0b9fc97
commit 4e942e489b
26 changed files with 295 additions and 1287 deletions

View File

@@ -73,11 +73,11 @@ FairMQMap XML::UserParser(stringstream& input, const string& deviceId, const str
namespace Helper
{
void PrintDeviceList(const boost::property_tree::ptree& tree, const std::string& formatFlag)
void PrintDeviceList(const boost::property_tree::ptree& tree, const string& formatFlag)
{
string deviceIdKey;
// do a first loop just to print the device-id in json input
// do a first loop just to print the device-id in json input
for (const auto& p : tree)
{
if (p.first == "devices")
@@ -88,23 +88,23 @@ void PrintDeviceList(const boost::property_tree::ptree& tree, const std::string&
if (key != "")
{
deviceIdKey = key;
LOG(TRACE) << "Found config for device key '" << deviceIdKey << "' in JSON input";
LOG(DEBUG) << "Found config for device key '" << deviceIdKey << "' in JSON input";
}
else
{
deviceIdKey = q.second.get<string>("id");
LOG(TRACE) << "Found config for device id '" << deviceIdKey << "' in JSON input";
LOG(DEBUG) << "Found config for device id '" << deviceIdKey << "' in JSON input";
}
}
}
if (p.first == "device")
{
//get id attribute to choose the device
// get id attribute to choose the device
if (formatFlag == "xml")
{
deviceIdKey = p.second.get<string>("<xmlattr>.id");
LOG(TRACE) << "Found config for '" << deviceIdKey << "' in XML input";
LOG(DEBUG) << "Found config for '" << deviceIdKey << "' in XML input";
}
if (formatFlag == "json")
@@ -113,12 +113,12 @@ void PrintDeviceList(const boost::property_tree::ptree& tree, const std::string&
if (key != "")
{
deviceIdKey = key;
LOG(TRACE) << "Found config for device key '" << deviceIdKey << "' in JSON input";
LOG(DEBUG) << "Found config for device key '" << deviceIdKey << "' in JSON input";
}
else
{
deviceIdKey = p.second.get<string>("id");
LOG(TRACE) << "Found config for device id '" << deviceIdKey << "' in JSON input";
LOG(DEBUG) << "Found config for device id '" << deviceIdKey << "' in JSON input";
}
}
}
@@ -428,7 +428,7 @@ void SocketParser(const boost::property_tree::ptree& tree, vector<FairMQChannel>
void PrintPropertyTree(const boost::property_tree::ptree& tree, int level)
{
for (const auto& p : tree) {
std::cout << std::setw(level+1) << level << ": " << p.first << " " << p.second.get_value<string>() << std::endl;
cout << setw(level+1) << level << ": " << p.first << " " << p.second.get_value<string>() << endl;
PrintPropertyTree(p.second.get_child(""), level + 1);
}
}

View File

@@ -8,30 +8,27 @@
/*
* File: FairMQProgOptions.cxx
* Author: winckler
*
*
* Created on March 11, 2015, 10:20 PM
*/
#include "FairMQProgOptions.h"
#include <algorithm>
#include "FairMQParser.h"
#include "FairMQSuboptParser.h"
#include "FairMQLogger.h"
#include <algorithm>
#include <iostream>
using namespace std;
FairMQProgOptions::FairMQProgOptions()
: FairProgOptions()
, fMQParserOptions("MQ-Device parser options")
, fMQOptionsInCfg("MQ-Device options")
, fMQOptionsInCmd("MQ-Device options")
, fMQParserOptions("FairMQ config parser options")
, fMQCmdOptions("FairMQ device options")
, fFairMQMap()
, fHelpTitle("***** FAIRMQ Program Options ***** ")
, fVersion("Beta version 0.1")
, fChannelInfo()
, fMQKeyMap()
// , fSignalMap() //string API
{
}
@@ -39,86 +36,51 @@ FairMQProgOptions::~FairMQProgOptions()
{
}
void FairMQProgOptions::ParseAll(const std::vector<std::string>& cmdLineArgs, bool allowUnregistered)
int FairMQProgOptions::ParseAll(const vector<string>& cmdLineArgs, bool allowUnregistered)
{
std::vector<const char*> argv(cmdLineArgs.size());
vector<const char*> argv(cmdLineArgs.size());
std::transform(cmdLineArgs.begin(), cmdLineArgs.end(), argv.begin(), [](const std::string& str)
transform(cmdLineArgs.begin(), cmdLineArgs.end(), argv.begin(), [](const string& str)
{
return str.c_str();
});
ParseAll(argv.size(), const_cast<char**>(argv.data()), allowUnregistered);
return ParseAll(argv.size(), const_cast<char**>(argv.data()), allowUnregistered);
}
void FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool allowUnregistered)
int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool allowUnregistered)
{
// init description
InitOptionDescription();
// parse command line options
if (FairProgOptions::ParseCmdLine(argc, argv, fCmdLineOptions, fVarMap, allowUnregistered))
{
// ParseCmdLine return 0 if help or version cmd not called. return 1 if called
exit(EXIT_SUCCESS);
}
// if txt/INI configuration file enabled then parse it as well
if (fUseConfigFile)
{
// check if file exist
if (fs::exists(fConfigFile))
{
if (FairProgOptions::ParseCfgFile(fConfigFile.string(), fConfigFileOptions, fVarMap, allowUnregistered))
{
// ParseCfgFile return -1 if cannot open or read config file. It return 0 otherwise
LOG(ERROR) << "Could not parse config";
exit(EXIT_FAILURE);
}
}
else
{
LOG(ERROR) << "config file '" << fConfigFile << "' not found";
exit(EXIT_FAILURE);
}
}
if (fVarMap.count("print-options"))
{
PrintOptionsRaw();
exit(EXIT_SUCCESS);
// ParseCmdLine returns 0 if no immediate switches found.
return 1;
}
// if these options are provided, do no further checks and let the device handle them
if (fVarMap.count("print-channels") || fVarMap.count("version"))
{
fair::mq::logger::DefaultConsoleSetFilter(fSeverityMap.at("NOLOG"));
return;
fair::Logger::SetConsoleSeverity("nolog");
return 0;
}
string severity = GetValue<string>("severity");
string logFile = GetValue<string>("log-to-file");
bool color = GetValue<bool>("color");
string verbosity = GetValue<string>("verbosity");
string logFile = GetValue<string>("log-to-file");
bool color = GetValue<bool>("log-color");
// check if the provided verbosity level is valid, otherwise set to DEBUG
if (fSeverityMap.count(verbosity) == 0)
{
LOG(ERROR) << " verbosity level '" << verbosity << "' unknown, it will be set to DEBUG";
verbosity = "DEBUG";
}
fair::Logger::SetVerbosity(verbosity);
if (logFile != "")
{
fair::mq::logger::ReinitLogger(false, logFile, fSeverityMap.at(verbosity));
fair::mq::logger::DefaultConsoleSetFilter(fSeverityMap.at("NOLOG"));
fair::Logger::InitFileSink(logFile, severity);
fair::Logger::SetConsoleSeverity("nolog");
}
else
{
if (!color)
{
fair::mq::logger::ReinitLogger(false);
}
fair::mq::logger::DefaultConsoleSetFilter(fSeverityMap.at(verbosity));
fair::Logger::SetConsoleColor(color);
fair::Logger::SetConsoleSeverity(severity);
}
// check if one of required MQ config option is there
@@ -140,9 +102,9 @@ void FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool a
LOG(WARN) << "FairMQProgOptions: no channels configuration provided via neither of:";
for (const auto& p : MQParserKeys)
{
LOG(WARN) << " --" << p;
LOG(WARNING) << " --" << p;
}
LOG(WARN) << "No channels will be created (You can create them manually).";
LOG(warn) << "No channels will be created (You can create them manually).";
}
else
{
@@ -180,10 +142,8 @@ void FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool a
}
else
{
LOG(ERROR) << "mq-config command line called but file extension '"
<< ext
<< "' not recognized. Program will now exit";
exit(EXIT_FAILURE);
LOG(error) << "mq-config command line called but file extension '" << ext << "' not recognized. Program will now exit";
return 1;
}
}
}
@@ -213,6 +173,8 @@ void FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool a
}
FairProgOptions::PrintOptions();
return 0;
}
int FairMQProgOptions::Store(const FairMQMap& channels)
@@ -237,7 +199,7 @@ void FairMQProgOptions::UpdateChannelInfo()
fChannelInfo.clear();
for (const auto& c : fFairMQMap)
{
fChannelInfo.insert(std::make_pair(c.first, c.second.size()));
fChannelInfo.insert(make_pair(c.first, c.second.size()));
}
}
@@ -275,104 +237,64 @@ void FairMQProgOptions::UpdateMQValues()
UpdateVarMap<string>(methodKey, channel.GetMethod());
UpdateVarMap<string>(addressKey, channel.GetAddress());
UpdateVarMap<string>(transportKey, channel.GetTransport());
//UpdateVarMap<string>(sndBufSizeKey, to_string(channel.GetSndBufSize()));// string API
UpdateVarMap<int>(sndBufSizeKey, channel.GetSndBufSize());
//UpdateVarMap<string>(rcvBufSizeKey, to_string(channel.GetRcvBufSize()));// string API
UpdateVarMap<int>(rcvBufSizeKey, channel.GetRcvBufSize());
//UpdateVarMap<string>(sndKernelSizeKey, to_string(channel.GetSndKernelSize()));// string API
UpdateVarMap<int>(sndKernelSizeKey, channel.GetSndKernelSize());
//UpdateVarMap<string>(rcvKernelSizeKey, to_string(channel.GetRcvKernelSize()));// string API
UpdateVarMap<int>(rcvKernelSizeKey, channel.GetRcvKernelSize());
//UpdateVarMap<string>(rateLoggingKey,to_string(channel.GetRateLogging()));// string API
UpdateVarMap<int>(rateLoggingKey, channel.GetRateLogging());
/*
LOG(DEBUG) << "Update MQ parameters of variable map";
LOG(DEBUG) << "key = " << typeKey <<"\t value = " << GetValue<string>(typeKey);
LOG(DEBUG) << "key = " << methodKey <<"\t value = " << GetValue<string>(methodKey);
LOG(DEBUG) << "key = " << addressKey <<"\t value = " << GetValue<string>(addressKey);
LOG(DEBUG) << "key = " << sndBufSizeKey << "\t value = " << GetValue<int>(sndBufSizeKey);
LOG(DEBUG) << "key = " << rcvBufSizeKey <<"\t value = " << GetValue<int>(rcvBufSizeKey);
LOG(DEBUG) << "key = " << sndKernelSizeKey << "\t value = " << GetValue<int>(sndKernelSizeKey);
LOG(DEBUG) << "key = " << rcvKernelSizeKey <<"\t value = " << GetValue<int>(rcvKernelSizeKey);
LOG(DEBUG) << "key = " << rateLoggingKey <<"\t value = " << GetValue<int>(rateLoggingKey);
*/
index++;
}
UpdateVarMap<int>(p.first + ".numSockets", index);
UpdateVarMap<int>("chans." + p.first + ".numSockets", index);
}
}
int FairMQProgOptions::NotifySwitchOption()
int FairMQProgOptions::ImmediateOptions()
{
if (fVarMap.count("help"))
{
std::cout << fHelpTitle << std::endl << fVisibleOptions;
cout << "===== FairMQ Program Options =====" << endl << fVisibleOptions;
return 1;
}
if (fVarMap.count("print-options"))
{
PrintOptionsRaw();
return 1;
}
return 0;
}
void FairMQProgOptions::FillOptionDescription(boost::program_options::options_description& options)
{
options.add_options()
("id", po::value<string>(), "Device ID (required argument).")
("io-threads", po::value<int >()->default_value(1), "Number of I/O threads.")
("transport", po::value<string>()->default_value("zeromq"), "Transport ('zeromq'/'nanomsg').")
("config", po::value<string>()->default_value("static"), "Config source ('static'/<config library filename>).")
("network-interface", po::value<string>()->default_value("default"), "Network interface to bind on (e.g. eth0, ib0..., default will try to detect the interface of the default route).")
("config-key", po::value<string>(), "Use provided value instead of device id for fetching the configuration from the config file.")
("catch-signals", po::value<int >()->default_value(1), "Enable signal handling (1/0).")
("initialization-timeout", po::value<int >()->default_value(120), "Timeout for the initialization in seconds (when expecting dynamic initialization).")
("port-range-min", po::value<int >()->default_value(22000), "Start of the port range for dynamic initialization.")
("port-range-max", po::value<int >()->default_value(32000), "End of the port range for dynamic initialization.")
("log-to-file", po::value<string>()->default_value(""), "Log output to a file.")
("print-channels", po::value<bool >()->implicit_value(true), "Print registered channel endpoints in a machine-readable format (<channel name>:<min num subchannels>:<max num subchannels>)")
("shm-segment-size", po::value<size_t>()->default_value(2000000000), "Shared memory: size of the shared memory segment (in bytes).")
("rate", po::value<float >()->default_value(0.), "Rate for conditional run loop (Hz).")
("session", po::value<string>()->default_value("default"), "Session name.")
;
}
void FairMQProgOptions::InitOptionDescription()
{
// Id required in command line if config txt file not enabled
if (fUseConfigFile)
{
FillOptionDescription(fMQOptionsInCmd);
FillOptionDescription(fMQOptionsInCfg);
}
else
{
FillOptionDescription(fMQOptionsInCmd);
}
fMQCmdOptions.add_options()
("id", po::value<string>(), "Device ID (required argument).")
("io-threads", po::value<int >()->default_value(1), "Number of I/O threads.")
("transport", po::value<string>()->default_value("zeromq"), "Transport ('zeromq'/'nanomsg').")
("config", po::value<string>()->default_value("static"), "Config source ('static'/<config library filename>).")
("network-interface", po::value<string>()->default_value("default"), "Network interface to bind on (e.g. eth0, ib0..., default will try to detect the interface of the default route).")
("config-key", po::value<string>(), "Use provided value instead of device id for fetching the configuration from the config file.")
("initialization-timeout", po::value<int >()->default_value(120), "Timeout for the initialization in seconds (when expecting dynamic initialization).")
("port-range-min", po::value<int >()->default_value(22000), "Start of the port range for dynamic initialization.")
("port-range-max", po::value<int >()->default_value(32000), "End of the port range for dynamic initialization.")
("log-to-file", po::value<string>()->default_value(""), "Log output to a file.")
("print-channels", po::value<bool >()->implicit_value(true), "Print registered channel endpoints in a machine-readable format (<channel name>:<min num subchannels>:<max num subchannels>)")
("shm-segment-size", po::value<size_t>()->default_value(2000000000), "Shared memory: size of the shared memory segment (in bytes).")
("rate", po::value<float >()->default_value(0.), "Rate for conditional run loop (Hz).")
("session", po::value<string>()->default_value("default"), "Session name.")
;
fMQParserOptions.add_options()
("config-xml-string", po::value<vector<string>>()->multitoken(), "XML input as command line string.")
// ("config-xml-file", po::value<string>(), "XML input as file.")
("config-json-string", po::value<vector<string>>()->multitoken(), "JSON input as command line string.")
// ("config-json-file", po::value<string>(), "JSON input as file.")
("mq-config", po::value<string>(), "JSON/XML input as file. The configuration object will check xml or json file extention and will call the json or xml parser accordingly")
(FairMQParser::SUBOPT::OptionKeyChannelConfig, po::value<std::vector<std::string>>()->multitoken()->composing(), "Configuration of single or multiple channel(s) by comma separated key=value list")
(FairMQParser::SUBOPT::OptionKeyChannelConfig, po::value<vector<string>>()->multitoken()->composing(), "Configuration of single or multiple channel(s) by comma separated key=value list")
;
AddToCmdLineOptions(fGenericDesc);
AddToCmdLineOptions(fMQOptionsInCmd);
AddToCmdLineOptions(fGeneralDesc);
AddToCmdLineOptions(fMQCmdOptions);
AddToCmdLineOptions(fMQParserOptions);
if (fUseConfigFile)
{
AddToCfgFileOptions(fMQOptionsInCfg, false);
AddToCfgFileOptions(fMQParserOptions, false);
}
}
int FairMQProgOptions::UpdateChannelMap(const string& channelName, int index, const string& member, const string& val)
@@ -409,45 +331,6 @@ int FairMQProgOptions::UpdateChannelMap(const string& channelName, int index, co
}
}
/*
// string API
int FairMQProgOptions::UpdateChannelMap(const string& channelName, int index, const string& member, const string& val)
{
if (member == "type")
{
fFairMQMap.at(channelName).at(index).UpdateType(val);
return 0;
}
if (member == "method")
{
fFairMQMap.at(channelName).at(index).UpdateMethod(val);
return 0;
}
if (member == "address")
{
fFairMQMap.at(channelName).at(index).UpdateAddress(val);
return 0;
}
else
{
if (member == "sndBufSize" || member == "rcvBufSize" || member == "rateLogging")
{
UpdateChannelMap(channelName,index,member,ConvertTo<int>(val));
}
//if we get there it means something is wrong
LOG(ERROR) << "update of FairMQChannel map failed for the following key: "
<< channelName<<"."<<index<<"."<<member;
return 1;
}
}
*/
// ----------------------------------------------------------------------------------
int FairMQProgOptions::UpdateChannelMap(const string& channelName, int index, const string& member, int val)
{
if (member == "sndBufSize")
@@ -469,9 +352,8 @@ int FairMQProgOptions::UpdateChannelMap(const string& channelName, int index, co
}
else
{
//if we get there it means something is wrong
LOG(ERROR) << "update of FairMQChannel map failed for the following key: "
<< channelName << "." << index << "." << member;
// if we get there it means something is wrong
LOG(ERROR) << "update of FairMQChannel map failed for the following key: " << channelName << "." << index << "." << member;
return 1;
}
}

View File

@@ -18,16 +18,15 @@
#include <fairmq/EventManager.h>
#include "FairProgOptions.h"
#include "FairMQChannel.h"
#include <unordered_map>
#include <functional>
#include <map>
#include <set>
#include <mutex>
#include <string>
#include "FairProgOptions.h"
#include "FairMQChannel.h"
namespace fair
{
namespace mq
@@ -43,17 +42,15 @@ class FairMQProgOptions : public FairProgOptions
{
protected:
using FairMQMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
//using signal_type = boost::signals2::signal<void(const std::string&, const std::string&)>;// string API
//using signal_type_ptr = boost::shared_ptr<signal_type>;// string API
public:
FairMQProgOptions();
virtual ~FairMQProgOptions();
void ParseAll(const std::vector<std::string>& cmdLineArgs, bool allowUnregistered);
// parse command line and txt/INI configuration file.
int ParseAll(const std::vector<std::string>& cmdLineArgs, bool allowUnregistered);
// parse command line.
// default parser for the mq-configuration file (JSON/XML) is called if command line key mq-config is called
virtual void ParseAll(const int argc, char const* const* argv, bool allowUnregistered = false);
int ParseAll(const int argc, char const* const* argv, bool allowUnregistered = false) override;
// external parser, store function
template <typename T, typename ...Args>
@@ -81,93 +78,11 @@ class FairMQProgOptions : public FairProgOptions
return fChannelInfo;
}
// to customize title of the executable help command line
void SetHelpTitle(const std::string& title)
{
fHelpTitle = title;
}
// to customize the executable version command line
void SetVersion(const std::string& version)
{
fVersion = version;
}
// store key-value of type T into variable_map.
// store key-value of type T into variable_map.
// If key is found in fMQKeyMap, update the FairMQChannelMap accordingly
// Note that the fMQKeyMap is filled:
// - if UpdateChannelMap(const FairMQMap& map) method is called
// - if UpdateChannelMap(const FairMQMap& map) method is called
// - if UserParser template method is called (it is called in the ParseAll method if json or xml MQ-config files is provided)
/* // string API
//overload for string literal
int UpdateValue(const std::string& key, const char* val) // string API
{
UpdateValue(key,std::string(val));
return 0;
}
// overload for string values
int UpdateValue(const std::string& key, const std::string& val) // string API
{
try
{
if (fVarMap.count(key))
{
if (!FairMQ::is_this_type<std::string>(fVarMap.at(key)))
{
LOG(ERROR) << "You try to update a value as string (for key="<< key <<") while it has been defined with a different type in the option description.";
abort();
}
// update variable map
UpdateVarMap(key,val);
if (fMQKeyMap.count(key))
{
std::string channelName;
int index = 0;
std::string member;
std::tie(channelName, index, member) = fMQKeyMap.at(key);
UpdateChannelMap(channelName, index, member, val);
}
// execute stored function of a given key if exist
//if (std::is_same<T, int>::value || std::is_same<T, std::string>::value)//if one wants to restrict type
if (fSignalMap.count(key))
EmitUpdate(key,val);
return 0;
}
else
{
LOG(ERROR) <<"UpdatedValue failed because the provided key '"
<<key
<<"' is not found in the variable map";
return 1;
}
}
catch (std::exception& e)
{
LOG(ERROR) << "Caught exception on key "<<key;
abort();
}
return 0;
}
*/
//overload for string literal
/*int UpdateValue(const std::string& key, const char* val) // string API
{
UpdateValue<std::string>(key,val);
return 0;
}*/
// specialization/overloading for string, pass by const ref
int UpdateValue(const std::string& key, const std::string& val) // string API
@@ -214,9 +129,7 @@ class FairMQProgOptions : public FairProgOptions
}
else
{
LOG(ERROR) << "UpdatedValue failed because the provided key '"
<< key
<< "' is not found in the variable map";
LOG(error) << "UpdateValue failed: key '" << key << "' not found in the variable map";
return 1;
}
return 0;
@@ -284,30 +197,14 @@ class FairMQProgOptions : public FairProgOptions
fEvents.Unsubscribe<fair::mq::PropertyChangeAsString, std::string>(subscriber);
}
/*
template <typename F>
void Subscribe(const std::string& key, F&& func)
{
if (fVarMap.count(key))
{
//if key-value not yet found, then add it
if (fSignalMap.find(key) == fSignalMap.end())
fSignalMap.emplace(key, boost::make_shared<signal_type>());
(*fSignalMap.at(key)).connect(std::forward<F>(func));
}
}
*/
// replace FairMQChannelMap, and update variable map accordingly
int UpdateChannelMap(const FairMQMap& map);
protected:
po::options_description fMQCmdOptions;
po::options_description fMQParserOptions;
po::options_description fMQOptionsInCfg;
po::options_description fMQOptionsInCmd;
FairMQMap fFairMQMap;
std::string fHelpTitle;
std::string fVersion;
// map of read channel info - channel name - number of subchannels
std::unordered_map<std::string, int> fChannelInfo;
@@ -315,36 +212,20 @@ class FairMQProgOptions : public FairProgOptions
using MQKey = std::tuple<std::string, int, std::string>;//store key info
std::map<std::string, MQKey> fMQKeyMap;// key=full path - val=key info
virtual int NotifySwitchOption(); // for custom help & version printing
int ImmediateOptions() override; // for custom help & version printing
void InitOptionDescription();
// fill boost option description with the standard options
static void FillOptionDescription(po::options_description& options);
// read FairMQChannelMap and insert/update corresponding values in variable map
// create key for variable map as follow : channelName.index.memberName
void UpdateMQValues();
int Store(const FairMQMap& channels);
private:
/*
// string API
std::map<std::string, signal_type_ptr > fSignalMap;
void EmitUpdate(const std::string& key, const char* val)
{
EmitUpdate(key,std::string(val));
}
void EmitUpdate(const std::string& key, const std::string& val)
{
(*fSignalMap.at(key))(key,val);
}
*/
template<typename T>
void EmitUpdate(const std::string& key, T val)
{
//compile time check whether T is const char* or char*, and in that case a compile time error is thrown.
static_assert(!std::is_same<T,const char*>::value || !std::is_same<T, char*>::value,
static_assert(!std::is_same<T,const char*>::value || !std::is_same<T, char*>::value,
"In template member FairMQProgOptions::EmitUpdate<T>(key,val) the types const char* or char* for the calback signatures are not supported.");
fEvents.Emit<fair::mq::PropertyChange, T>(key, val);
fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetStringValue(key));

View File

@@ -15,49 +15,30 @@
#include "FairProgOptions.h"
#include <iomanip>
#include <sstream>
using namespace std;
FairProgOptions::FairProgOptions() :
fVarMap(),
fGenericDesc("Generic options description"),
fConfigDesc("Configuration options description"),
fEnvironmentDesc("Environment variables"),
fHiddenDesc("Hidden options description"),
fCmdLineOptions("Command line options"),
fConfigFileOptions("Configuration file options"),
fSeverityMap(),
fVisibleOptions("Visible options"),
fConfigMutex(),
fVerbosityLevel("INFO"),
fUseConfigFile(false),
fConfigFile()
FairProgOptions::FairProgOptions()
: fVarMap()
, fGeneralDesc("General options")
, fCmdLineOptions("Command line options")
, fVisibleOptions("Visible options")
, fConfigMutex()
{
LOG(NOLOG) << "";// temporary hack to prevent throwing exception when accessing empty sinklist --> fixed me
fGenericDesc.add_options()
fGeneralDesc.add_options()
("help,h", "produce help")
("version,v", "print version")
("verbosity", po::value<std::string>(&fVerbosityLevel)->default_value("DEBUG"), "Verbosity level : TRACE, DEBUG, RESULTS, INFO, WARN, ERROR, STATE, NOLOG")
("log-color", po::value<bool>()->default_value(true), "logger color: true or false")
("severity", po::value<string>()->default_value("debug"), "Log severity level : trace, debug, info, state, warn, error, fatal, nolog")
("verbosity", po::value<string>()->default_value("medium"), "Log verbosity level : veryhigh, high, medium, low")
("color", po::value<bool>()->default_value(true), "Log color (true/false)")
("print-options", po::value<bool>()->implicit_value(true), "print options in machine-readable format (<option>:<computed-value>:<type>:<description>)");
fSeverityMap["TRACE"] = fair::mq::logger::SeverityLevel::TRACE;
fSeverityMap["DEBUG"] = fair::mq::logger::SeverityLevel::DEBUG;
fSeverityMap["RESULTS"] = fair::mq::logger::SeverityLevel::RESULTS;
fSeverityMap["INFO"] = fair::mq::logger::SeverityLevel::INFO;
fSeverityMap["WARN"] = fair::mq::logger::SeverityLevel::WARN;
fSeverityMap["ERROR"] = fair::mq::logger::SeverityLevel::ERROR;
fSeverityMap["STATE"] = fair::mq::logger::SeverityLevel::STATE;
fSeverityMap["NOLOG"] = fair::mq::logger::SeverityLevel::NOLOG;
}
/// Destructor
FairProgOptions::~FairProgOptions()
{
}
/// //////////////////////////////////////////////////////////////////////////////////////////////////////
/// Add option descriptions
int FairProgOptions::AddToCmdLineOptions(const po::options_description optDesc, bool visible)
{
@@ -69,61 +50,11 @@ int FairProgOptions::AddToCmdLineOptions(const po::options_description optDesc,
return 0;
}
int FairProgOptions::AddToCfgFileOptions(const po::options_description optDesc, bool visible)
{
//if UseConfigFile() not yet called, then enable it with required file name to be provided by command line
if (!fUseConfigFile)
{
UseConfigFile();
}
fConfigFileOptions.add(optDesc);
if (visible)
{
fVisibleOptions.add(optDesc);
}
return 0;
}
//*
po::options_description& FairProgOptions::GetCmdLineOptions()
{
return fCmdLineOptions;
}
po::options_description& FairProgOptions::GetCfgFileOptions()
{
return fConfigFileOptions;
}
po::options_description& FairProgOptions::GetEnvironmentOptions()
{
return fEnvironmentDesc;
}
int FairProgOptions::AddToEnvironmentOptions(const po::options_description optDesc)
{
fEnvironmentDesc.add(optDesc);
return 0;
}
void FairProgOptions::UseConfigFile(const string& filename)
{
fUseConfigFile = true;
if (filename.empty())
{
fConfigDesc.add_options()
("config-file", po::value<boost::filesystem::path>(&fConfigFile)->required(), "Path to configuration file (required argument)");
AddToCmdLineOptions(fConfigDesc);
}
else
{
fConfigFile = filename;
}
}
/// //////////////////////////////////////////////////////////////////////////////////////////////////////
/// Parser
int FairProgOptions::ParseCmdLine(const int argc, char const* const* argv, const po::options_description& desc, po::variables_map& varmap, bool allowUnregistered)
{
// get options from cmd line and store in variable map
@@ -140,9 +71,9 @@ int FairProgOptions::ParseCmdLine(const int argc, char const* const* argv, const
po::store(po::parse_command_line(argc, argv, desc), varmap);
}
// call the virtual NotifySwitchOption method to handle switch options like e.g. "--help" or "--version"
// Handles options like "--help" or "--version"
// return 1 if switch options found in varmap
if (NotifySwitchOption())
if (ImmediateOptions())
{
return 1;
}
@@ -156,89 +87,8 @@ int FairProgOptions::ParseCmdLine(const int argc, char const* const* argv, const
return ParseCmdLine(argc, argv, desc, fVarMap, allowUnregistered);
}
int FairProgOptions::ParseCfgFile(ifstream& ifs, const po::options_description& desc, po::variables_map& varmap, bool allowUnregistered)
{
if (!ifs)
{
LOG(ERROR) << "can not open configuration file";
return -1;
}
else
{
po::store(parse_config_file(ifs, desc, allowUnregistered), varmap);
po::notify(varmap);
}
return 0;
}
int FairProgOptions::ParseCfgFile(const string& filename, const po::options_description& desc, po::variables_map& varmap, bool allowUnregistered)
{
ifstream ifs(filename.c_str());
if (!ifs)
{
LOG(ERROR) << "can not open configuration file: " << filename;
return -1;
}
else
{
po::store(parse_config_file(ifs, desc, allowUnregistered), varmap);
po::notify(varmap);
}
return 0;
}
int FairProgOptions::ParseCfgFile(const string& filename, const po::options_description& desc, bool allowUnregistered)
{
return ParseCfgFile(filename,desc,fVarMap,allowUnregistered);
}
int FairProgOptions::ParseCfgFile(ifstream& ifs, const po::options_description& desc, bool allowUnregistered)
{
return ParseCfgFile(ifs,desc,fVarMap,allowUnregistered);
}
int FairProgOptions::ParseEnvironment(const function<string(string)>& environmentMapper)
{
po::store(po::parse_environment(fEnvironmentDesc, environmentMapper), fVarMap);
po::notify(fVarMap);
return 0;
}
int FairProgOptions::PrintHelp() const
{
cout << fVisibleOptions << "\n";
return 0;
}
int FairProgOptions::PrintOptionsRaw()
{
MapVarValInfo_t mapInfo;
for (const auto& m : fVarMap)
{
mapInfo[m.first] = GetVariableValueInfo(m.second);
}
for (const auto& p : mapInfo)
{
string keyStr;
string valueStr;
string typeInfoStr;
string defaultStr;
string emptyStr;
keyStr = p.first;
tie(valueStr, typeInfoStr, defaultStr, emptyStr) = p.second;
auto option = fCmdLineOptions.find_nothrow(keyStr, false);
cout << keyStr << ":" << valueStr << ":" << typeInfoStr << ":" << (option ? option->description() : "<not found>") << endl;
}
return 0;
}
int FairProgOptions::PrintOptions()
{
// //////////////////////////////////
// Method to overload.
// -> loop over variable map and print its content
// -> In this example the following types are supported:
@@ -283,20 +133,27 @@ int FairProgOptions::PrintOptions()
// formatting and printing
LOG(DEBUG) << setfill ('*') << setw (totalLength + 3) << "*";// +3 because of string " = "
string PrintOptionsTitle = " Configuration ";
stringstream ss;
ss << "\n";
ss << setfill('*') << setw(totalLength + 3) << "*" << "\n"; // +3 because of string " = "
string title = " Configuration ";
int leftSpaceLength = 0;
int rightSpaceLength = 0;
int leftTitleShiftLength = 0;
int rightTitleShiftLength = 0;
leftTitleShiftLength = PrintOptionsTitle.length() / 2;
leftTitleShiftLength = title.length() / 2;
if ((PrintOptionsTitle.length()) % 2)
if ((title.length()) % 2)
{
rightTitleShiftLength = leftTitleShiftLength + 1;
}
else
{
rightTitleShiftLength = leftTitleShiftLength;
}
leftSpaceLength = (totalLength + 3) / 2 - leftTitleShiftLength;
if ((totalLength + 3) % 2)
@@ -308,11 +165,11 @@ int FairProgOptions::PrintOptions()
rightSpaceLength = (totalLength + 3) / 2 - rightTitleShiftLength;
}
LOG(DEBUG) << setfill ('*') << setw(leftSpaceLength) << "*"
<< setw(PrintOptionsTitle.length()) << PrintOptionsTitle
<< setfill ('*') << setw(rightSpaceLength) << "*";
ss << setfill ('*') << setw(leftSpaceLength) << "*"
<< setw(title.length()) << title
<< setfill ('*') << setw(rightSpaceLength) << "*" << "\n";
LOG(DEBUG) << setfill ('*') << setw (totalLength+3) << "*";
ss << setfill ('*') << setw (totalLength+3) << "*" << "\n";
for (const auto& p : mapinfo)
{
@@ -323,36 +180,46 @@ int FairProgOptions::PrintOptions()
string emptyStr;
keyStr = p.first;
tie(valueStr, typeInfoStr, defaultStr, emptyStr) = p.second;
LOG(DEBUG) << std::setfill(' ')
<< setw(maxLength1st) << left
<< p.first << " = "
<< setw(maxLength2nd)
<< valueStr
<< setw(maxLengthTypeInfo)
<< typeInfoStr
<< setw(maxLengthDefault)
<< defaultStr
<< setw(maxLengthEmpty)
<< emptyStr;
ss << setfill(' ')
<< setw(maxLength1st) << left
<< p.first << " = "
<< setw(maxLength2nd)
<< valueStr
<< setw(maxLengthTypeInfo)
<< typeInfoStr
<< setw(maxLengthDefault)
<< defaultStr
<< setw(maxLengthEmpty)
<< emptyStr
<< "\n";
}
LOG(DEBUG) << setfill ('*') << setw (totalLength + 3) << "*";// +3 for " = "
ss << setfill ('*') << setw(totalLength + 3) << "*";// +3 for " = "
LOG(DEBUG) << ss.str();
return 0;
}
int FairProgOptions::NotifySwitchOption()
int FairProgOptions::PrintOptionsRaw()
{
// Method to overload.
if (fVarMap.count("help"))
MapVarValInfo_t mapInfo;
for (const auto& m : fVarMap)
{
cout << "***** FAIR Program Options ***** \n" << fVisibleOptions;
return 1;
mapInfo[m.first] = GetVariableValueInfo(m.second);
}
if (fVarMap.count("version"))
for (const auto& p : mapInfo)
{
cout << "alpha version 0.0\n";
return 1;
string keyStr;
string valueStr;
string typeInfoStr;
string defaultStr;
string emptyStr;
keyStr = p.first;
tie(valueStr, typeInfoStr, defaultStr, emptyStr) = p.second;
auto option = fCmdLineOptions.find_nothrow(keyStr, false);
cout << keyStr << ":" << valueStr << ":" << typeInfoStr << ":" << (option ? option->description() : "<not found>") << endl;
}
return 0;

View File

@@ -16,27 +16,28 @@
#define FAIRPROGOPTIONS_H
#include "FairMQLogger.h"
#include "FairProgOptionsHelper.h"
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include "FairProgOptionsHelper.h"
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <iterator>
#include <mutex>
#include <tuple>
/*
* FairProgOptions abstract base class
* parse command line, configuration file options as well as environment variables.
*
* parse command line, configuration file options.
*
* The user defines in the derived class the option descriptions and
* the pure virtual ParseAll() method
*
*
* class MyOptions : public FairProgOptions
* {
* public :
* public :
* MyOptions() : FairProgOptions()
* {
* fCmdlineOptions.add(fGenericDesc);
@@ -80,13 +81,7 @@ class FairProgOptions
// add options_description
int AddToCmdLineOptions(const po::options_description optDesc, bool visible = true);
int AddToCfgFileOptions(const po::options_description optDesc, bool visible = true);
int AddToEnvironmentOptions(const po::options_description optDesc);
po::options_description& GetCmdLineOptions();
po::options_description& GetCfgFileOptions();
po::options_description& GetEnvironmentOptions();
void UseConfigFile(const std::string& filename = "");
// get value corresponding to the key
template<typename T>
@@ -108,9 +103,8 @@ class FairProgOptions
}
catch (std::exception& e)
{
LOG(ERROR) << "Exception thrown for the key '" << key << "'";
LOG(ERROR) << e.what();
this->PrintHelp();
LOG(error) << "Exception thrown for the key '" << key << "'";
LOG(error) << e.what();
}
return val;
@@ -168,44 +162,26 @@ class FairProgOptions
int ParseCmdLine(const int argc, char const* const* argv, const po::options_description& desc, po::variables_map& varmap, bool allowUnregistered = false);
int ParseCmdLine(const int argc, char const* const* argv, const po::options_description& desc, bool allowUnregistered = false);
int ParseCfgFile(const std::string& filename, const po::options_description& desc, po::variables_map& varmap, bool allowUnregistered = false);
int ParseCfgFile(const std::string& filename, const po::options_description& desc, bool allowUnregistered = false);
int ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, po::variables_map& varmap, bool allowUnregistered = false);
int ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, bool allowUnregistered = false);
int ParseEnvironment(const std::function<std::string(std::string)>&);
virtual void ParseAll(const int argc, char const* const* argv, bool allowUnregistered = false) = 0;// TODO change return type to bool and propagate to executable
virtual int ParseAll(const int argc, char const* const* argv, bool allowUnregistered = false) = 0;// TODO change return type to bool and propagate to executable
virtual int PrintOptions();
virtual int PrintOptionsRaw();
int PrintHelp() const;
protected:
// options container
po::variables_map fVarMap;
// basic description categories
po::options_description fGenericDesc;
po::options_description fConfigDesc;
po::options_description fEnvironmentDesc;
po::options_description fHiddenDesc;
po::options_description fGeneralDesc;
// Description of cmd line and simple configuration file (configuration file like txt, but not like xml json ini)
po::options_description fCmdLineOptions;
po::options_description fConfigFileOptions;
// Description which is printed in help command line
// to handle logger severity
std::map<std::string, fair::mq::logger::SeverityLevel> fSeverityMap;
po::options_description fVisibleOptions;
mutable std::mutex fConfigMutex;
std::string fVerbosityLevel;
bool fUseConfigFile;
boost::filesystem::path fConfigFile;
virtual int NotifySwitchOption();
virtual int ImmediateOptions() = 0;
// UpdateVarMap() and replace() --> helper functions to modify the value of variable map after calling po::store
template<typename T>
@@ -227,7 +203,7 @@ class FairProgOptions
VarValInfo_t GetVariableValueInfo(const po::variable_value& varValue);
static void Max(int &val, const int &comp)
static void Max(int& val, const int& comp)
{
if (comp > val)
{

View File

@@ -1,48 +1,44 @@
<fairMQOptions>
<device name="merger" id="merger" >
<channel name="two_inputs_channel" >
<socket name="input1" >
<type>pull</type>
<method>bind</method>
<address>tcp://*:5569</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
<socket name="input2" >
<type>pull</type>
<method>bind</method>
<address>tcp://*:5570</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
</channel>
<channel name="one_output_channel" >
<socket name="output1" >
<type>push</type>
<method>connect</method>
<address>tcp://*:5571</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
</channel>
<device name="merger" id="merger">
<channel name="two_inputs_channel">
<socket name="input1">
<type>pull</type>
<method>bind</method>
<address>tcp://*:5569</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
<socket name="input2">
<type>pull</type>
<method>bind</method>
<address>tcp://*:5570</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
</channel>
<channel name="one_output_channel">
<socket name="output1">
<type>push</type>
<method>connect</method>
<address>tcp://*:5571</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
</channel>
</device>
<device name="sink" id="sink" >
<channel name="one_input" >
<socket name="input1" >
<type>pull</type>
<method>bind</method>
<address>tcp://localhost:5571</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
<device name="sink" id="sink">
<channel name="one_input">
<socket name="input1">
<type>pull</type>
<method>bind</method>
<address>tcp://localhost:5571</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
</channel>
</device>
</fairMQOptions>

View File

@@ -10,19 +10,13 @@
#include "FairMQParser.h"
#include "FairMQProgOptions.h"
//////////////////////////////////////////////////////////////
// tests
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
// Parse xml from file
int testXML1(FairMQProgOptions* config)
{
LOG(INFO)<<"--------- test XML1 ---------\n";
std::string filename;
std::string XMLrootNode;
filename=config->GetValue<std::string>("config-xml-file");
XMLrootNode=config->GetValue<std::string>("xml.config.node.root");
std::string id=config->GetValue<std::string>("id");
@@ -30,12 +24,11 @@ int testXML1(FairMQProgOptions* config)
// other xml parser test
config->UserParser<FairMQParser::MQXML2>(filename);
config->UserParser<FairMQParser::MQXML3>(filename,"merger");
LOG(INFO)<<"--------- test XML1 end ---------\n";
return 0;
}
// Parse xml from command line
int testXML2(FairMQProgOptions* config)
{
@@ -44,14 +37,14 @@ int testXML2(FairMQProgOptions* config)
std::string XMLrootNode;
std::string id=config->GetValue<std::string>("id");
XMLrootNode=config->GetValue<std::string>("xml.config.node.root");
// Note: convert the vector<string> into one string with GetStringValue(key)
XML=config->GetStringValue("config-xml-string");
std::stringstream iss;
iss << XML;
config->UserParser<FairMQParser::XML>(iss,id,XMLrootNode);
LOG(INFO)<<"--------- test XML2 end ---------\n";
return 0;
}
@@ -63,12 +56,12 @@ int testJSON1(FairMQProgOptions* config)
std::string filename;
std::string JSONrootNode;
std::string id=config->GetValue<std::string>("id");
filename=config->GetValue<std::string>("config-json-file");
JSONrootNode=config->GetValue<std::string>("json.config.node.root");
config->UserParser<FairMQParser::JSON>(filename,id,JSONrootNode);
LOG(INFO)<<"--------- test JSON1 end ---------\n";
return 0;
}
@@ -81,59 +74,63 @@ int testJSON2(FairMQProgOptions* config)
std::string JSONrootNode;
std::string id=config->GetValue<std::string>("id");
JSONrootNode=config->GetValue<std::string>("json.config.node.root");
// Note: convert the vector<string> into one string with GetStringValue(key)
JSON=config->GetStringValue("config-json-string");
std::stringstream iss;
iss << JSON;
config->UserParser<FairMQParser::JSON>(iss,id,JSONrootNode);
LOG(INFO)<<"--------- test JSON2 end ---------\n";
return 0;
}
//////////////////////////////////////////////////////////////
/// main
//////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
FairMQProgOptions* config= new FairMQProgOptions();
try
{
po::options_description format_desc("XML or JSON input");
format_desc.add_options()
format_desc.add_options()
("xml.config.node.root", po::value<std::string>()->default_value("fairMQOptions"), "xml root node ")
("json.config.node.root", po::value<std::string>()->default_value("fairMQOptions"), "json root node ")
;
config->AddToCmdLineOptions(format_desc);
// Parse command line
if(config->ParseAll(argc,argv))
if (config->ParseAll(argc,argv))
{
return 0;
}
// Set severity level (Default is 0=DEBUG)
int verbosity = config->GetValue<int>("verbosity");
FairMQLogger::Level lvl=static_cast<FairMQLogger::Level>(verbosity);
int severity = config->GetValue<int>("severity");
FairMQLogger::Level lvl=static_cast<FairMQLogger::Level>(severity);
SET_LOGGER_LEVEL(lvl);
// Parse xml or json from cmd line or file
if(config->GetVarMap().count("config-xml-file"))
if (config->GetVarMap().count("config-xml-file"))
{
testXML1(config);
if(config->GetVarMap().count("config-xml-string"))
}
if (config->GetVarMap().count("config-xml-string"))
{
testXML2(config);
if(config->GetVarMap().count("config-json-file"))
}
if (config->GetVarMap().count("config-json-file"))
{
testJSON1(config);
if(config->GetVarMap().count("config-json-string"))
}
if (config->GetVarMap().count("config-json-string"))
{
testJSON2(config);
}
}
catch (std::exception& e)
{
@@ -142,9 +139,3 @@ int main(int argc, char** argv)
}
return 0;
}

View File

@@ -15,17 +15,16 @@
//////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
{
try
{
FairMQProgOptions config;
po::options_description format_desc("XML input");
format_desc.add_options()
("xml.config.node.root", po::value<std::string>()->default_value("fairMQOptions"), "xml root node ")
;
po::options_description io_file_opt_desc("I/O file Options");
io_file_opt_desc.add_options()
("input.file.name", po::value<std::string>(), "input file name")
@@ -38,21 +37,20 @@ int main(int argc, char** argv)
config.AddToCmdLineOptions(format_desc,true);
config.AddToCmdLineOptions(io_file_opt_desc,true);
config.EnableCfgFile();// UseConfigFile (by default config file is not defined)
config.AddToCfgFileOptions(format_desc,false);//false because already added to visible
config.AddToCfgFileOptions(io_file_opt_desc,false);
// Parse command line and config file
if(config.ParseAll(argc,argv))
return 0;
// Set severity level (Default is 0=DEBUG)
int verbosity=config.GetValue<int>("verbosity");
FairMQLogger::Level lvl=static_cast<FairMQLogger::Level>(verbosity);
int severity = config.GetValue<int>("severity");
FairMQLogger::Level lvl = static_cast<FairMQLogger::Level>(severity);
SET_LOGGER_LEVEL(lvl);
// parse XML file
std::string filename;
std::string XMLrootNode;
@@ -61,8 +59,6 @@ int main(int argc, char** argv)
XMLrootNode=config.GetValue<std::string>("xml.config.node.root");
std::string id=config.GetValue<std::string>("id");
config.UserParser<FairMQParser::XML>(filename,id,XMLrootNode);
}
catch (std::exception& e)
{
@@ -71,9 +67,3 @@ int main(int argc, char** argv)
}
return 0;
}

View File

@@ -6,6 +6,6 @@ VERBOSE="DEBUG"
JSONCONFIGFILE="@CMAKE_BINARY_DIR@/bin/config/ex1-sampler-sink.json"
########################## start DEVICE
DEVICE="runConfigExample --transport $TRANSPORT --verbosity $VERBOSE"
DEVICE="runConfigExample --transport $TRANSPORT --severity $VERBOSE"
DEVICE+=" --id sampler1 --mq-config $JSONCONFIGFILE"
@CMAKE_BINARY_DIR@/bin/$DEVICE