Accessing logger streams directly

Help
jmo
2014-02-27
2014-03-05
  • jmo

    jmo - 2014-02-27

    Hi,

    I would like to access log streams directly rather than via the BOOST_LOG_SEV macro, which (in my version, admittedly not the latest) actually expands to a for loop over zero or more logging streams, which makes it impossible to pass the stream/s into a method.

    Here's the very ugly "hack" I've come up with to deal with this, basically using operator overloads to force a function call on each logging ostream:

    template<typename Func>
    inline void operator|(std::ostream& os, Func func)
    {
        func(os);    
    }
    
    template<class Logger, typename... Args>
    void Log(Logger& logger, SeverityLevels sev, Args... args)
    {
       BOOST_LOG_SEV(logger, sev) | 
           std::bind(
               [](std::ostream& os, Args... args2)->void 
               { 
                   // do cool recursive stuff with os, args 
               },
               std::placeholders::_1, 
               args...); 
    }
    

    Is anyone able to offer a better solution here? Aside from being ugly, my use of std::bind is copying the variable argument list by value every time - not ideal at all.

    Thanks in advance
    Jess

     
  • Andrey Semashev

    Andrey Semashev - 2014-02-27

    The library caches the stream that is used by BOOST_LOG_SEV, and there is no public API for accessing it. But you don't have to use it anyway, you can construct the log message in any convenient way. For example here is how you can do it without the macro and with a standalone stream. You can use std::ostringstream or snprintf or whatever other tool you like for that. Just set the "Message" attribute when you composed the message string (record_ostream does that automatically).

     
    Last edit: Andrey Semashev 2014-02-27
  • jmo

    jmo - 2014-03-05

    Hi Andrey, thanks for that and I've done as you suggested (that is, opened the record directly and used record_ostream as per the example). Works great and avoids my hack. I also used the opportunity to upgrade our boost libraries to 1.55 so I can follow your doc with a little more confidence!

    I now want to add an enum attribute to each log record that indicates the type of record, as a lookup to description, action etc. to be consumed by a monitoring GUI at the other end of a syslog sink. It looks like the way to attach arbitrary attributes to log records is only by defining a new logger, as per your "writing your own sources" example, which seems to use my requirement (except you use a string tag, not an enum) as an example. I can certainly adapt that to my needs but do shout if there's a better way.

    Thanks again for the quick response.

    Jess

     
  • Andrey Semashev

    Andrey Semashev - 2014-03-05

    If you're not using channels already, you can use channel loggers for that purpose.

     
  • jmo

    jmo - 2014-03-05

    Yes I'm using a channel severity logger. But I need a tag that changes with individual log messages, not static per logger. Hence the example you provided is more suitable.

     
  • jmo

    jmo - 2014-03-05

    Actually, looking at your example Andrey it looks like the attiribute_values() method returns a mutable attribute set in 1.55 (which I can just insert into), and there's also the logging::add_value convenience function for inserting. I think perhaps in the old version I was using the record attributes were const only, but in any case I really should've checked the docs first!

    Thanks as always for the pointers.

     

Log in to post a comment.