Menu

No channel output string

Anonymous
2013-05-28
2013-06-20
1 2 3 > >> (Page 1 of 3)
  • Anonymous

    Anonymous - 2013-05-28

    Hi,

    I was playing a bit with the latest boost.log version and the tutorial.

    In case I test execute the code below:

    // Define a global logger
    BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(my_logger, src::channel_logger_mt<std::string >, (keywords::channel = "general"))
    int main(void){
        // Put message to the "net" channel
        BOOST_LOG_CHANNEL(my_logger::get(), "net")  << "Connection established";
        return 0;
    }
    

    I receive the following output:

          Connection established

    Question:

    Why is the channel string ("general") as specified in the global logger macro in the log record stated as a hex-decimal string " ".

    For my understanding the following log record should be generated:

          Connection shut down

    Any suggestions?

    Thank you in advanced for your help!

    Br

     
  • Anonymous

    Anonymous - 2013-05-28

    …ohh sorry,

    the expected log record should of course be:

       Connection shut down

    BR

     
  • Andrey Semashev

    Andrey Semashev - 2013-05-28

    is not the channel but the current thread id. To display channel name you will have to setup a formatter that outputs one.

     
  • Anonymous

    Anonymous - 2013-05-29

    …thx, it works now!

     
  • Anonymous

    Anonymous - 2013-05-29

    Hi!

    As stated in the initial post I'm using a global logger of type channel_logger_mt.

    Is there a MACRO beside the BOOST_LOG_SCOPED_LOGGER_TAG to change the channel string of a logger?

    For instance: I've two cpp-modules for which I would like to set module-wide (file-wide) a channel name. This means, in case I enter a method of module "A", I want the log records to have the channel string"A" contained. In case I visit a method of modue "B", I want the log records made in this method to have the channel string "B" contained.
    Unfortunately the macro (b]BOOST_LOG_SCOPED_LOGGER_TAG  seems not to be the suitable solution, as this macro is - in my understanding and tests acknowledged this behavior - just method-scoped!

    Okay, I could set manually always the channel manually in each modules class with MyLogger::get().channel("A") but this is to inconvenient for me, as It would be necessary to repeat this for each class which are definined/declared in one single module.

    So, I just need  a macro, to set module/file-wide the channel.

    Thanks for your help so far!

    BR

     
  • Andrey Semashev

    Andrey Semashev - 2013-05-29

    There is the BOOST_LOG_CHANNEL macro that sets the channel name, but I would suggest you use different loggers per different modules. If you don't have many modules, this approach may turn out to be more efficient, performance-wise.

     
  • Andrey Semashev

    Andrey Semashev - 2013-05-29

    So, I just need a macro, to set module/file-wide the channel.

    There are no module-wide attributes. If the logger is global, it only has one channel attribute with one value, which, obvoiusly, correspond to a single module at a time. You can either change the value every time you cross the module boundaries, or use module-specific loggers, each having the channel name of the respective module. Depending on your definition of "modules", this can mean dll-local loggers, static loggers or loggers in anonymous namespaces, object-specific loggers, etc.

     
  • Anonymous

    Anonymous - 2013-05-29

    Hi.

    I now this macro. My itention was to set the channel name once. So it wouldn't be anymore necessary to specify for each log record channel name. Actually I'm using a severity_channel_logger_mt logger. This means, I would have to specify for each record the severity level plus the channel name -> redundancy!

    Actually I would like prefer to use a global logger, as this make things simple in my software, because I use the command pattern and I have almost 40 different command class. This means, I have to instantiate for each command class a logger as member in case I don't use the global logger approach. The global approach reduces the "complexity".

    Any suggestions?

    But thank you so far.

     
  • Andrey Semashev

    Andrey Semashev - 2013-05-29

    Having object-specific loggers don't increase code complexity that much. This is even easier if you have a common base class of all your commands, so that you can add the logger to the base and initialize it with the channel name passed from the derived class. Aside from that the use of the logger is the same. I don't know how appropriate this solution for your case, but I would definitely prefer object-specific loggers to the global one, when possible.

     
  • Anonymous

    Anonymous - 2013-05-29

    …thanks for your suggestion. You're right regarding the base class and to add a logger instance to the class.

    Thx so far.

     
  • Anonymous

    Anonymous - 2013-05-31

    HI Andrey,

    To filter log records by channel name, I'm using the mechanism referenced as "initialization from a settings container" like illustrated in the code snippet below:

    /** Boost.Log-specific macro used to define a placeholder for the channel attribute
      */
    BOOST_LOG_ATTRIBUTE_KEYWORD(channelPlaceholder, "Channel", std::string)

    BOOST_LOG_GLOBAL_LOGGER_INIT(MGPLogger, MGPLogger_t) {
    boost::shared_ptr< logging::core > core = logging::core::get();

        // Create a backend and attach a couple of streams to it
        boost::shared_ptr< sinks::text_ostream_backend > consoleBackend = boost::make_shared< sinks::text_ostream_backend >();
        // Output to the standard out stream -> use std::cout
        // Output to the standard logging stream -> use std::clog
        consoleBackend->add_stream(boost::shared_ptr< std::ostream >(&std::cout, logging::empty_deleter()));

        // Enable auto-flushing after each log record written
        consoleBackend->auto_flush(true);

        // Wrap it into the frontend and register in the core.
        // The backend requires synchronization in the frontend.
        typedef sinks::synchronous_sink< sinks::text_ostream_backend > console_sink_t;
        boost::shared_ptr< console_sink_t > consoleSink(new console_sink_t(consoleBackend));
        // Specify the format of the console log records
        consoleSink->set_formatter (
        expr::stream <<
        "     " <<
        channelPlaceholder <<
            expr::smessage
        );

        core->add_sink(consoleSink);

        src::severity_channel_logger_mt<LoggingSeverity, std::string> lg(keywords::channel = "Control", keywords::severity = SEV_INFO);
        return lg;
    }

    int main(void){

      // Initiate filtering settings
      logging::settings setts;
      setts = false;
      setts = "%Channel% = Network";

      logging::init_from_settings(setts);
             
      // Produce some log records to verify whether channel filtering works as expected
      BOOST_LOG_CHANNEL(GlobalLogger::get(), "Network") << "Log record produced by the \"Network\" channel";
      BOOST_LOG_CHANNEL(GlobalLogger::get(), "Control") << "Log record produced by the \"Control\" channel";
      BOOST_LOG_CHANNEL(GlobalLogger::get(), "Control") << "One more log record produced by the \"Network\" channel";
    (….)
    }

    The same behavior I receive also for my severity type if setting the filter options in the settings container:

    int main(void){

    setts = "%Severity% = FATAL";

      // Initiate filtering settings
      logging::settings setts;
      setts = false;
             setts = "%Severity% = FATAL";

      logging::init_from_settings(setts);
             
      // Produce some log records to verify whether channel filtering works as expected
      BOOST_LOG_SEV(GlobalLogger::get(), "FATAL") << "FATAL Log record  ";
      BOOST_LOG_SEV(GlobalLogger::get(), "WARNING") << "WARNING Log ";
      BOOST_LOG_SEV(GlobalLogger::get(), "FATAL") << "FATALOne more log record";

    (….)
    }

    I receive no log record outputs for both channel name and severity level filtering.

    Is it  necessary to specify a filter factory for the channel name (although std::string isn't a "user-defined" type) and the severity (which also a none-user-defined type, its an enum type) to define and add a filter factory?

    BR

     
  • Anonymous

    Anonymous - 2013-05-31

    …there is an copy-paste error in the post below: In the formatter there is no placeholder defined for the severity attribute…. actually it looks like as stated below:

    consoleSink->set_formatter (
        expr::stream <<
        "     " <<
        severityPlaceholder <<
        channelPlaceholder <<
            expr::smessage
        );

     
  • Andrey Semashev

    Andrey Semashev - 2013-05-31

    std::string attributes need not be registered, the library is aware of this type. Enums are user-defined types, so these attributes need to be registered.

    Your code doesn't seem to have any obvious mistakes but it's clearly incomplete. I didn't get what severity level type is, you use enums and strings in different places. If you could provide a complete compilable code snippet, so I'm able to reproduce the problem, I could be more helpful.

     
  • Anonymous

    Anonymous - 2013-05-31

    moment!

     
  • Anonymous

    Anonymous - 2013-05-31

    Hi.

    please find below the complete code which should compile without problems. BTW: The problem with the channel name-based filtering works now fine. Unfortunately the issue persists regarding to the "Severity-based"-filtering.

    #include <iostream>
    #include <fstream>
    #include <boost/log/common.hpp>
    #include <boost/log/expressions.hpp>
    #include <boost/log/sinks/text_file_backend.hpp>
    #include <boost/log/sinks/text_ostream_backend.hpp>
    #include <boost/log/sinks/sync_frontend.hpp>
    #include <boost/log/support/date_time.hpp>
    #include <boost/log/utility/empty_deleter.hpp>
    #include <boost/log/utility/setup/settings.hpp>
    #include <boost/log/utility/setup/from_settings.hpp>
    #include <boost/log/utility/setup/from_stream.hpp>
    #include <boost/log/utility/setup/filter_parser.hpp>
    #include <boost/log/trivial.hpp>
    namespace logging = boost::log;
    namespace sinks = boost::log::sinks;
    namespace src = boost::log::sources;
    namespace expr = boost::log::expressions;
    namespace attrs = boost::log::attributes;
    namespace keywords = boost::log::keywords;
    /**
     * Enumerates the supported severity levels
     * for logging.
     */
    enum LoggingSeverity {
        /**
         * Reports operation information while tracing through the code.
         */
        SEV_TRACE,  //!< SEVERITY_TRACE
        /**
         * Reports detailed information, typically of
         * interest only when diagnosing problems.
         */
        SEV_DEBUG,  //!< SEVERITY_DEBUG
        /**
         * Reports the succeeded execution of service operations.
         */
        SEV_INFO,   //!< SEVERITY_INFO
        /**
         * Reports the succeeded execution of
         * the service operations but which doesn't
         * produce the expected results.
         */
        SEV_WARNING,//!< SEVERITY_WARNING
        /**
         * Reports any error which doesn't stop
         * the execution of the service but which can
         * cause undefined behavior if the service is continued.
         */
        SEV_ERROR,  //!< SEVERITY_ERROR
        /**
         * Reports any error that doesn't permit
         * a reliable execution of the service or any error
         * which forces the shutdown of the service.
         */
        SEV_FATAL   //!< SEVERITY_FATAL
    };
    /**
     * Operator is used to put a human-friendly representation of the severity level
     * log record.
     */
    std::ostream& operator<< (std::ostream& strm, LoggingSeverity level);
    /**
     * User-defined severity and channel logger type.
     */
    typedef src::severity_channel_logger_mt<
            LoggingSeverity,     // the type of the severity level value
            std::string          // the type of the channel name value
    > MGPLogger_t;
    /**
     * Boost.Log specific macro necessary to use a global logger.
     */
    BOOST_LOG_GLOBAL_LOGGER(MGPLogger, MGPLogger_t)
    /**
     * User-defined macro wraps the Boost.Log-specific one
     */
    #define LOG(sev) \
            BOOST_LOG_SEV(MGPLogger::get(), sev)
    /**
     * Boost.Log-specific macro used to define a placeholder for the severity attribute
     */
    BOOST_LOG_ATTRIBUTE_KEYWORD(severityPlaceholder, "Severity", LoggingSeverity)
    /**
     * Boost.Log-specific macro used to define a placeholder for the channel attribute
     */
    BOOST_LOG_ATTRIBUTE_KEYWORD(channelPlaceholder, "Channel", std::string)
    std::ostream& operator<< (std::ostream& strm, LoggingSeverity level) {
        static const char* strings[] = {
            "TRACE",
            "DEBUG",
            "INFO",
            "WARNING",
            "ERRORR",
            "FATAL"
        };
        if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings))
            strm << strings[level];
        else
            strm << static_cast< int >(level);
        return strm;
    }
    /**
     * Boost.Log-specific macro to perform to initialize the global logger.
     */
    BOOST_LOG_GLOBAL_LOGGER_INIT(MGPLogger, MGPLogger_t) {
        logging::core::get()->add_global_attribute("MGPTLTAG", boost::log::attributes::constant< std::string > ("MGP TL"));
        // Add global attributs (Line ID; Timestamp etc)
        // logging::add_common_attributes();
        // ########## Create a text file sink ############# //
        // Get a pointer to the Boost::Log logging core of
        boost::shared_ptr< logging::core > core = logging::core::get();
        // ########## Create a console Sink ############# //
        // Create a backend and attach a couple of streams to it
        boost::shared_ptr< sinks::text_ostream_backend > consoleBackend = boost::make_shared< sinks::text_ostream_backend >();
        // Output to the standard out stream -> use std::cout
        // Output to the standard logging stream -> use std::clog
        consoleBackend->add_stream(boost::shared_ptr< std::ostream >(&std::cout, logging::empty_deleter()));
        // Enable auto-flushing after each log record written
        consoleBackend->auto_flush(true);
        // Wrap it into the frontend and register in the core.
        // The backend requires synchronization in the frontend.
        typedef sinks::synchronous_sink< sinks::text_ostream_backend > console_sink_t;
        boost::shared_ptr< console_sink_t > consoleSink(new console_sink_t(consoleBackend));
        // Specify the format of the console log records
        consoleSink->set_formatter (
                expr::stream <<
                "[" << expr::attr< std::string >("MGPTLTAG") << " - " <<
                expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%d-%m-%Y %H:%M:%S") <<
                " - " <<
                //expr::attr< std::string >("Channel") <<
                channelPlaceholder <<
                " - " <<
                expr::attr< LoggingSeverity >("Severity") <<
                //severityPlaceholder <<
                "] " <<
                expr::smessage
        );
        core->add_sink(consoleSink);
        MGPLogger_t lg(keywords::channel = "Control", keywords::severity = SEV_INFO);
        // Specify the channel name on construction, similarly as with the channel_logger
        return lg;
    }
    int main(void){
        // Initiate filtering settings
        logging::settings setts;
        setts["Core"]["DisableLogging"] = false;
        //setts["Core"]["Filter"] = "%Channel% = Landstrasse";  // <-> Works now fine!
        setts["Core"]["Filter"] = "%Severity% = WARNING"; // <- Doesn't work -> so maybe a factory has to be defined
        logging::init_from_settings(setts);
        BOOST_LOG_CHANNEL_SEV(MGPLogger::get(), "Autobahn", SEV_TRACE) << "Autobahn, SEV_TRACE";
        BOOST_LOG_CHANNEL_SEV(MGPLogger::get(), "Autobahn", SEV_DEBUG) << "Autobahn, SEV_DEBUG";
        BOOST_LOG_CHANNEL_SEV(MGPLogger::get(), "Landstrasse", SEV_INFO) << "2. Landstrasse, SEV_INFO";
        BOOST_LOG_CHANNEL_SEV(MGPLogger::get(), "Landstrasse", SEV_WARNING) << "Landstrasse, SEV_WARNING";
        return 0;
    }
    
     
  • Anonymous

    Anonymous - 2013-05-31

    …any ideas Andrey?

    Thanks so far!

     
  • Andrey Semashev

    Andrey Semashev - 2013-06-01

    As I suggested, you have to register your severity level enum in the library to be able to parse filters with it.

     
  • Anonymous

    Anonymous - 2013-06-03

    Hey Andrey,

    thanks for the hint! After the registration of a filter factory for the user-defined type the filtering works as expected.

    However another issure pop-up regarding the format of the log record in case the log record is specified with the settings feature as state below:

            (...)
            setts["Sinks.File.Destination"] = "TextFile";
        setts["Sinks.File.FileName"] = "MGPTL_%d%m%Y_%H%M%S_%2N.log";
        setts["Sinks.File.Target"] = "LogFiles/";
            // Here: this format is not applied -> just the default format is used, which means that just the message is logged.
        setts["Sinks.File"]["Format"] = "[%MGPTLTAG% - %TimeStamp% - %Channel% - %Severity%] %Message%";
        setts["Sinks.File"]["Filter"] =  "%Severity% = INFO";
        setts["Sinks.File.RotationSize"] = 1024; // 1 MiB
        setts["Sinks.File.AutoFlush"] = false;
        setts["Core"]["Filter"] =  "%Severity% != INFO & %Channel% = Fun | %Channel% = Bier ";
        BOOST_LOG_CHANNEL_SEV(chanSevLogger, "Fun", SEV_TRACE) << "SEV_TRACE";
        BOOST_LOG_CHANNEL_SEV(chanSevLogger, "Bier", SEV_WARNING) << "SEV_WARNING";
        BOOST_LOG_CHANNEL_SEV(chanSevLogger, "Fun", SEV_TRACE) << "SEV_TRACE";
        BOOST_LOG_CHANNEL_SEV(chanSevLogger, "Bier", SEV_INFO) << "SEV_INFO";
            (...)
    

    In case I use the settings

    setts = " %Message%";

    for the the formatter I just get the default message in the log file:

    SEV_INFO

    It is also necessary to specify a formatter factory and to register it afterwards in the core? If I understood the documentation correctly, then this isn't necessary.

    Any hints?

    Thanks for your help so far!

     
  • Andrey Semashev

    Andrey Semashev - 2013-06-03

    You have to register filter factory to enable your type support in the filter parser. Similarly, you have to register formatter factory to enable it in the formatter parser.

     
  • Anonymous

    Anonymous - 2013-06-03

    …arrrrrrrggg,

    I've found the issue: The boost log documentation seems not to be at the latest state…

    I just changed

    setts = " %Message%";

    to

    setts = " %Message%";

    and now its works!

    In the documentation http://boost-log.sourceforge.net/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup it is mentioned to use

    Format

    , but this won't work.

    Instead it is necessary to specify

    Formatter

    to trigger the core to use the specified log record format.

    Nevertheless, thanks so far!

     
  • Anonymous

    Anonymous - 2013-06-03

    …so, it isn't necessary to specify a "Formatter" factory for my case, that's why your response is a bit confusing…

     
  • Anonymous

    Anonymous - 2013-06-03

    the log records are no well formatted, except of the severity level string.

    SEV_INFO

    So  I've have to specify a new formatter factory for the severty level. But it is still necessary to change the keyword from "Format" to "Formatter".

     
  • Andrey Semashev

    Andrey Semashev - 2013-06-03

    The docs are correct, the parameter name is "Format". There was a bug in some early revisions (it was named "Formatter" for some time) but it is fixed in 2.0 release.

     
  • Anonymous

    Anonymous - 2013-06-03

    …good to know.

    I've to upgrade to boost log v2.

     
  • Anonymous

    Anonymous - 2013-06-03

    Hello Andrey,

    currently I'm using boost.log under Windows 7. In case I'm using file rotation and and specifying the "MaxSize" parameter my application crashes after the specified size of the directory containg the log files has been reached.

    Please consider the code below:

     (...)
           setts["Sinks.File.Destination"] = "TextFile";
        setts["Sinks.File.FileName"] = "MGPTL_%2N.log";
        setts["Sinks.File.Target"] = "LogFiles/";
        setts["Sinks.File"]["Format"] = "[%MGPTLTAG% - %TimeStamp% - %Channel% - %Severity%] %Message%";
        setts["Sinks.File"]["Filter"] =  "%Severity% = INFO";
        setts["Sinks.File.RotationSize"] = 10; // 1 MiB
        setts["Sinks.File.AutoFlush"] = false;
        setts["Sinks.File.ScanForFiles"] = "Matching";
        setts["Sinks.File.MaxSize"] = 200; // 200 bytes
        setts["Core"]["Filter"] =  "%Severity% != INFO & %Channel% = Fun | %Channel% = Bier ";
    (...)
    

    This means, in the situation where the directory size (here 200 bytes) has been reached, the oldest log file should  be deleted/overriden/replaced by boost log  in that directory. Unfortunately, the complete application crashed without any exception thrown.

    Do you know, what could be the issue?

    Greetings!

     
1 2 3 > >> (Page 1 of 3)

Log in to post a comment.