Skip to content

Source · fairmq/

ProgOptions.cxxsource

Described in Configuration and properties, Threads in a device, 1-1: sampler and sink, qc: quality control on demand, Control a device from code, Command-line options, Logging.

fairmq/ProgOptions.cxx453 lines · C++GitHub ↗
1/********************************************************************************2 * Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH  *3 *                                                                              *4 *              This software is distributed under the terms of the             *5 *              GNU Lesser General Public Licence (LGPL) version 3,             *6 *                  copied verbatim in the file "LICENSE"                       *7 ********************************************************************************/8/*9 * File:   ProgOptions.cxx10 * Author: winckler11 *12 * Created on March 11, 2015, 10:20 PM13 */14 15#include <fairmq/ProgOptions.h>16#include <fairmq/tools/Strings.h>17 18#include <boost/any.hpp>19#include <boost/regex.hpp>20 21#include <algorithm>22#include <exception>23#include <fairlogger/Logger.h>24#include <iomanip>25#include <iostream>26#include <sstream>27#include <utility> // pair28 29using namespace std;30using namespace fair::mq;31 32namespace po = boost::program_options;33 34struct ValInfo35{36    string value;37    string type;38    string origin;39};40 41namespace fair::mq42{43 44ValInfo ConvertVarValToValInfo(const po::variable_value& v)45{46    string origin;47 48    if (v.defaulted()) {49        origin = "[default]";50    } else if (v.empty()) {51        origin = "[empty]";52    } else {53        origin = "[provided]";54    }55 56    try {57        pair<string, string> info = PropertyHelper::GetPropertyInfo(v.value());58        return {info.first, info.second, origin};59    } catch (out_of_range& oor) {60        return {string("[unidentified_type]"), string("[unidentified_type]"), origin};61    }62}63 64string ConvertVarValToString(const po::variable_value& v)65{66    return ConvertVarValToValInfo(v).value;67}68 69ProgOptions::ProgOptions()70    : fAllOptions("FairMQ Command Line Options")71{72    fAllOptions.add_options()73        ("help,h",                                                      "Print help")74        ("version,v",                                                   "Print version")75        ("severity",      po::value<string>()->default_value(""),       "Log severity level (console): trace, debug, info, state, warn, error, fatal, nolog.")76        ("file-severity", po::value<string>()->default_value("debug"),  "Log severity level (file): trace, debug, info, state, warn, error, fatal, nolog")77        ("verbosity",     po::value<string>()->default_value("medium"), "Log verbosity level: veryhigh, high, medium, low")78        ("color",         po::value<bool  >()->default_value(true),     "Log color (true/false)")79        ("log-to-file",   po::value<string>()->default_value(""),       "Log output to a file.")80        ("print-options", po::value<bool  >()->implicit_value(true),    "Print options in machine-readable format (<option>:<computed-value>:<type>:<description>)");81 82    ParseDefaults();83}84 85void ProgOptions::ParseDefaults()86{87    vector<string> emptyArgs = {"dummy"};88 89    vector<const char*> argv(emptyArgs.size());90 91    transform(emptyArgs.begin(), emptyArgs.end(), argv.begin(), [](const string& str) {92        return str.c_str();93    });94 95    std::lock_guard<std::mutex> lock(fMtx);96    po::store(po::parse_command_line(argv.size(), const_cast<char**>(argv.data()), fAllOptions), fVarMap);97}98 99void ProgOptions::ParseAll(const vector<string>& cmdArgs, bool allowUnregistered)100{101    vector<const char*> argv(cmdArgs.size());102    transform(cmdArgs.begin(), cmdArgs.end(), argv.begin(), [](const string& str) {103        return str.c_str();104    });105    ParseAll(argv.size(), const_cast<char**>(argv.data()), allowUnregistered);106}107 108void ProgOptions::ParseAll(const int argc, char const* const* argv, bool allowUnregistered)109{110    lock_guard<mutex> lock(fMtx);111    // clear the container because it was filled with default values and subsequent calls to store() do not overwrite the existing values112    fVarMap.clear();113 114 115    po::command_line_parser parser(argc, argv);116 117    parser.options(fAllOptions);118 119    if (allowUnregistered) {120        parser.allow_unregistered();121    }122 123    using namespace po::command_line_style;124    style_t style = style_t(allow_short | short_allow_adjacent | short_allow_next | allow_long | long_allow_adjacent | long_allow_next | allow_sticky | allow_dash_for_short);125    parser.style(style);126 127    po::parsed_options parsed = parser.run();128 129    fUnregisteredOptions = po::collect_unrecognized(parsed.options, po::include_positional);130 131    po::store(parsed, fVarMap);132}133 134void ProgOptions::Notify()135{136    lock_guard<mutex> lock(fMtx);137    po::notify(fVarMap);138}139 140void ProgOptions::AddToCmdLineOptions(const po::options_description optDesc, bool /* visible */)141{142    lock_guard<mutex> lock(fMtx);143    fAllOptions.add(optDesc);144}145 146po::options_description& ProgOptions::GetCmdLineOptions()147{148    return fAllOptions;149}150 151int ProgOptions::Count(const string& key) const152{153    lock_guard<mutex> lock(fMtx);154    return fVarMap.count(key);155}156 157unordered_map<string, int> ProgOptions::GetChannelInfo() const158{159    lock_guard<mutex> lock(fMtx);160    return GetChannelInfoImpl();161}162 163unordered_map<string, int> ProgOptions::GetChannelInfoImpl() const164{165    unordered_map<string, int> info;166 167    boost::regex re("chans\\..*\\.type");168    for (const auto& m : fVarMap) {169        if (boost::regex_match(m.first, re)) {170            string chan = m.first.substr(6);171            string::size_type n = chan.find('.');172            string chanName = chan.substr(0, n);173 174            if (info.find(chanName) == info.end()) {175                info.emplace(chanName, 1);176            } else {177                info[chanName] = info[chanName] + 1;178            }179        }180    }181 182    return info;183}184 185vector<string> ProgOptions::GetPropertyKeys() const186{187    lock_guard<mutex> lock(fMtx);188 189    vector<string> keys;190 191    for (const auto& it : fVarMap) {192        keys.emplace_back(it.first.c_str());193    }194 195    return keys;196}197 198string ProgOptions::GetPropertyAsString(const string& key) const199{200    lock_guard<mutex> lock(fMtx);201 202    if (fVarMap.count(key)) {203        return ConvertVarValToString(fVarMap.at(key));204    } else {205        throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key));206    }207}208 209string ProgOptions::GetStringValue(const string& key) const210{211    lock_guard<mutex> lock(fMtx);212 213    if (fVarMap.count(key)) {214        return ConvertVarValToString(fVarMap.at(key));215    } else {216        LOG(warn) << "Config has no key: " << key << ". Returning default constructed object.";217        return string();218    }219}220 221string ProgOptions::GetPropertyAsString(const string& key, const string& ifNotFound) const222{223    lock_guard<mutex> lock(fMtx);224 225    if (fVarMap.count(key)) {226        return ConvertVarValToString(fVarMap.at(key));227    }228 229    return ifNotFound;230}231 232Properties ProgOptions::GetProperties(const string& q) const233{234    boost::regex re(q);235    Properties properties;236 237    lock_guard<mutex> lock(fMtx);238 239    for (const auto& m : fVarMap) {240        if (boost::regex_match(m.first, re)) {241            properties.emplace(m.first, m.second.value());242        }243    }244 245    if (properties.empty()) {246        LOG(warn) << "could not find anything with \"" << q << "\"";247    }248 249    return properties;250}251 252Properties ProgOptions::GetPropertiesStartingWith(const string& q) const253{254    Properties properties;255 256    lock_guard<mutex> lock(fMtx);257 258    for (const auto& m : fVarMap) {259        if (m.first.compare(0, q.length(), q) == 0) {260            properties.emplace(m.first, m.second.value());261        }262    }263 264    return properties;265}266 267map<string, string> ProgOptions::GetPropertiesAsString(const string& q) const268{269    boost::regex re(q);270    map<string, string> properties;271 272    lock_guard<mutex> lock(fMtx);273 274    for (const auto& m : fVarMap) {275        if (boost::regex_match(m.first, re)) {276            properties.emplace(m.first, PropertyHelper::ConvertPropertyToString(m.second.value()));277        }278    }279 280    if (properties.empty()) {281        LOG(warn) << "could not find anything with \"" << q << "\"";282    }283 284    return properties;285}286 287map<string, string> ProgOptions::GetPropertiesAsStringStartingWith(const string& q) const288{289    map<string, string> properties;290 291    lock_guard<mutex> lock(fMtx);292 293    for (const auto& m : fVarMap) {294        if (m.first.compare(0, q.length(), q) == 0) {295            properties.emplace(m.first, PropertyHelper::ConvertPropertyToString(m.second.value()));296        }297    }298 299    return properties;300}301 302void ProgOptions::SetProperties(const Properties& input)303{304    unique_lock<mutex> lock(fMtx);305 306    map<string, boost::program_options::variable_value>& vm = fVarMap;307    for (const auto& m : input) {308        vm[m.first].value() = m.second;309    }310 311    lock.unlock();312 313    for (const auto& m : input) {314        PropertyHelper::fEventEmitters.at(m.second.type())(fEvents, m.first, m.second);315        fEvents.Emit<PropertyChangeAsString, string>(m.first, PropertyHelper::ConvertPropertyToString(m.second));316    }317}318 319bool ProgOptions::UpdateProperties(const Properties& input)320{321    unique_lock<mutex> lock(fMtx);322 323    for (const auto& m : input) {324        if (fVarMap.count(m.first) == 0) {325            LOG(debug) << "UpdateProperties failed, no property found with key '" << m.first << "'";326            return false;327        }328    }329 330    map<string, boost::program_options::variable_value>& vm = fVarMap;331    for (const auto& m : input) {332        vm[m.first].value() = m.second;333    }334 335    lock.unlock();336 337    for (const auto& m : input) {338        PropertyHelper::fEventEmitters.at(m.second.type())(fEvents, m.first, m.second);339        fEvents.Emit<PropertyChangeAsString, string>(m.first, PropertyHelper::ConvertPropertyToString(m.second));340    }341 342    return true;343}344 345void ProgOptions::DeleteProperty(const string& key)346{347    lock_guard<mutex> lock(fMtx);348 349    map<string, boost::program_options::variable_value>& vm = fVarMap;350    vm.erase(key);351}352 353void ProgOptions::AddChannel(const string& name, const Channel& channel)354{355    lock_guard<mutex> lock(fMtx);356    unordered_map<string, int> existingChannels = GetChannelInfoImpl();357    int index = 0;358    if (existingChannels.count(name) > 0) {359        index = existingChannels.at(name);360    }361 362    string prefix = fair::mq::tools::ToString("chans.", name, ".", index, ".");363 364    SetVarMapValue<string>(string(prefix + "type"), channel.GetType());365    SetVarMapValue<string>(string(prefix + "method"), channel.GetMethod());366    SetVarMapValue<string>(string(prefix + "address"), channel.GetAddress());367    SetVarMapValue<string>(string(prefix + "transport"), channel.GetTransportName());368    SetVarMapValue<int>(string(prefix + "sndBufSize"), channel.GetSndBufSize());369    SetVarMapValue<int>(string(prefix + "rcvBufSize"), channel.GetRcvBufSize());370    SetVarMapValue<int>(string(prefix + "sndKernelSize"), channel.GetSndKernelSize());371    SetVarMapValue<int>(string(prefix + "rcvKernelSize"), channel.GetRcvKernelSize());372    SetVarMapValue<int>(string(prefix + "linger"), channel.GetLinger());373    SetVarMapValue<int>(string(prefix + "rateLogging"), channel.GetRateLogging());374    SetVarMapValue<int>(string(prefix + "portRangeMin"), channel.GetPortRangeMin());375    SetVarMapValue<int>(string(prefix + "portRangeMax"), channel.GetPortRangeMax());376    SetVarMapValue<bool>(string(prefix + "autoBind"), channel.GetAutoBind());377}378 379void ProgOptions::PrintHelp() const380{381    cout << fAllOptions << endl;382}383 384void ProgOptions::PrintOptions() const385{386    map<string, ValInfo> mapinfo;387 388    int maxLenKey = 0;389    int maxLenValue = 0;390    int maxLenType = 0;391    int maxLenDefault = 0;392 393    std::lock_guard<std::mutex> lock(fMtx);394 395    for (const auto& m : fVarMap) {396        maxLenKey = max(maxLenKey, static_cast<int>(m.first.length()));397 398        ValInfo valinfo = ConvertVarValToValInfo(m.second);399        mapinfo[m.first] = valinfo;400 401        maxLenValue = max(maxLenValue, static_cast<int>(valinfo.value.length()));402        maxLenType = max(maxLenType, static_cast<int>(valinfo.type.length()));403        maxLenDefault = max(maxLenDefault, static_cast<int>(valinfo.origin.length()));404    }405 406    if (maxLenValue > 100) {407        maxLenValue = 100;408    }409 410    for (const auto& o : fUnregisteredOptions) {411        LOG(debug) << "detected unregistered option: " << o;412    }413 414    stringstream ss;415    ss << "Configuration: \n";416 417    for (const auto& p : mapinfo) {418        string type("<" + p.second.type + ">");419        ss << setfill(' ') << left420           << setw(maxLenKey) << p.first << " = "421           << setw(maxLenValue) << p.second.value << " "422           << setw(maxLenType + 2) << type << " "423           << setw(maxLenDefault) << p.second.origin424           << "\n";425    }426 427    LOG(debug) << ss.str();428}429 430void ProgOptions::PrintOptionsRaw() const431{432    std::lock_guard<std::mutex> lock(fMtx);433 434    const vector<boost::shared_ptr<po::option_description>>& options = fAllOptions.options();435 436    for (const auto& o : options) {437        ValInfo value;438        if (fVarMap.count(o->canonical_display_name())) {439            value = ConvertVarValToValInfo(fVarMap[o->canonical_display_name()]);440        }441 442        string description = o->description();443 444        replace(description.begin(), description.end(), '\n', ' ');445 446        cout << o->long_name() << ":" << value.value << ":" << (value.type.empty() ? "<unknown>" : value.type) << ":" << description << endl;447    }448}449 450} // namespace fair::mq451 452template void fair::mq::ProgOptions::SetProperty<std::string>(const std::string& key, std::string val);453template void fair::mq::ProgOptions::SetProperty<int>(const std::string& key, int val);