Search code examples
c++loggingboostboost-logboost-logging

Boost Log: Interaction of log settings file and code configuration


I have a nice format and a console log:

auto fmtStream = expressions::stream
  << "LineID: " << expressions::attr<unsigned int>("LineID") << " "
  << "Message: " << expressions::message:

boost::log::add_console_log(std::cout, keywords::format = fmtStream);

The format stream is of course somewhat longer.. Now I want to give a user to configure the logging:

std::ifstream file("log.conf");
init_from_stream(file);

A lot of formatting used in fmtStream is not possible using the format string in the config file.

How can I give the user the possibility to modify the console sink, e.g. add a filter? But I want to keep the format string as a default.

Possibilities I see for that:

1) Give the console log that I define in my code a name. The user could now modify it with a sink of the same name.

2) Set a default format that is taken for all sinks. But according to Boost Log changing the default logging::core formatter? this is not possible.

3) Any other ideas?

Thanks!


Solution

  • init_from_stream and init_from_settings functions will initialize the library as specified in the settings. These functions are designed to configure the library from scratch, so they will add new sinks with the specified settings, including filters and formatters. If all you need is to customize formatter for your existing sink and not allow full logging configuration then you should interpret the settings file yourself.

    You can parse the settings file with the parse_settings function. From it you will receive a settings (or wsettings) object which you can analyze and modify as described here and here (sorry for the bad formatting in the reference docs). Since you're probably not planning to support all sinks and parameters supported by Boost.Log, you are not bound to the semantics Boost.Log puts in the parameters and can interpret the settings in any way you want. For instance, you may choose to only read the sink formatter:

    boost::log::settings setts = boost::log::parse_settings(file);
    if (boost::optional<std::string> fmt = setts["MySink"]["Format"])
    {
        // Sink format is specified in the setting file
    }
    

    Now, to turn this format string into a formatter, you will need the parse_formatter function (the string format is described here). This function returns a formatter object that you can install into your sink, provided that you saved a pointer to it.

    auto sink = boost::log::add_console_log(std::cout, keywords::format = fmtStream);
    boost::log::settings setts = boost::log::parse_settings(file);
    if (boost::optional<std::string> fmt = setts["MySink"]["Format"])
    {
        sink->set_formatter(boost::log::parse_formatter(fmt.get()));
    }
    

    There's one more thing to remember though. If you're using attribute values of custom types in your formatter, like enums for severity, for example, you will have to register those types in the library before parsing the formatter. This way the parser will be able to create a formatter that knows your types and uses appropriate formatting operators. There's a tutorial describing how to do that.