Menu

Decorating log messages

2013-03-19
2013-06-03
  • Juan Fernandez

    Juan Fernandez - 2013-03-19

    Hopefully there is someone out there who can help me. I want to use boost.log in my application for logging. The application consists out of a exe and various dlls. Some log entries shall carry metainformation. The metainformation shall not be writting into the logfile (first sink) but displayed in the output window of my application. There I want to show the log text, decorated with further information such as a kind of hyperlink. Actually those log calls must be decorated with:
    - a link target string
    - a enum, defining the kind of link
    - a C++ Pointer wrapping one of my objects (needed for the target link resolvement)

    So what I would need is: BOOST_LOG(lg) << magic("link destination", 2, &myObject) << "Some  log message";

    Is there any way to realise this with boost? I have tried with attributes, but it seems that attributes are not made for this purpose. Furthermore I need to implement my own processor in the sink, so I can build my specific links in the output window.

     
  • Andrey Semashev

    Andrey Semashev - 2013-03-19

    Attributes are intended for attaching any kind of information to log records, and it seems your case fits just fine. I'm not sure what's the nature of your links and how they should be processed. However, you should be able to define your class "link" that contains all relevant data of the link and attach it to records:

    BOOST_LOG(lg) << add_value("Link", link(2, &myObject)) << "Some log message";
    

    This, however, won't allow you to filter records based on this "Link" attribute. If you need this, you'll have to add it as a scoped attribute or create a logger feature that will manage it.

    Depending on the nature of the links, you can add formatting for your link class or some special processing in your custom sink backend.

     
  • Juan Fernandez

    Juan Fernandez - 2013-03-19

    My project is dealing with a complex data modell and the links are references into the data model. So when the user in the GUI starts some action, a algorithm is started, working on the data modell. Within the modell data components are referencing each other (just like a relational data base). It can occurr that the data modell in incomplete and some links/references cannot be resolved. There are heaps of possible link failures throughout the algorithms. When the software detects a link failure, I want to:
    a) log just a message into file (-> e.g. "Link xyz could not be resolved")
    b) print a message in the application output window with link resolution ( e.g."Link xyz could not be resolved: <MyLink>") So I want to have the same logging message in the logfile and the output window. But the output window has further information from where the dead link was generated and thus I need the meta information passed through the logging.

    If I understood correct I can use the attributes, use the default file backend sink for logging and create another sink which uses my own customized backend. This backend than visits the attributes in the consume method, extracts the link information and passes all the data back into my application. The way I pass back this is not important for the understanding and will be implemented in the consume method.

    Is this the recommended practice for my use case?

     
  • Andrey Semashev

    Andrey Semashev - 2013-03-19

    Yes, that's right. Be careful though not to initiate logging while in consume method of the sink.

     
  • Juan Fernandez

    Juan Fernandez - 2013-03-20

    Thanks for your help so far. Going further in my project I have the requirement to insert the link information at some specific position in the log text. What I would need is the feature like this:

    BOOST_LOG(lg) << "First part of text" << add_value("Link", link(2, &myObject)) << "some other part of text message";

    But now attributes cannot be used. They are attached to the log message, but it is not possible to mix text and attributes and keep the order. Is there any workaround or technique to solve this?

     
  • Andrey Semashev

    Andrey Semashev - 2013-03-20

    You should use formatters to compose the final representation of the message.

     
  • Juan Fernandez

    Juan Fernandez - 2013-03-20

    I have looked on formatters and they seem to be static to me. As the link information can occurr anywhere in the log stream, formatters don't seem to work. Have I missed anything on them?

    e.g.:
    BOOST_LOG(lg) << "Simple log message";
    BOOST_LOG(lg) << add_value("Link", link(2, &myObject)) << "Link at the beginning";
    BOOST_LOG(lg) << "First part of text" << add_value("Link", link(2, &myObject)) << "some other part of text message";
    BOOST_LOG(lg) << "Link at the end" << add_value("Link", link(2, &myObject));
    BOOST_LOG(lg) << "Two links" << add_value("Link", link(2, &myObject))<< " some text between" << add_value("Link", link(2, &myObject));

     
  • Andrey Semashev

    Andrey Semashev - 2013-03-20

    If you want to embed links into the message text then your best bet is to output a format string with placeholders as the message text and postprocess it in your custom formatter (you'll have to write one). Something like:

    BOOST_LOG(lg) << add_value("Link1", link(2, &myObject1))  << add_value("Link2", link(2, &myObject2)) << "Two links %Link1% some text between %Link2% some other part of text message";
    

    However you typically put your attributes in some designated part of the log message so that it is easily parseable. For this kind of usage the formatters provided out of the box fit best.

     
  • Andrey Semashev

    Andrey Semashev - 2013-03-20

    Oh, as a side note, if you intend to show this message to the user (in a GUI, for example), you'll probably want to avoid using the message text altogether. The common requirement for UI is internationalization support, which is typically achieved by keying messages on different languages on an identifier. You could pass this identifier as another attribute, then fetch the corresponding text template from the strings database (whatever it is in your case) and then insert links at appropriate places of the template. The log message text can be used purely for internal diagnostic purposes then.

     
  • Juan Fernandez

    Juan Fernandez - 2013-03-20

    Hello Andrey,

    I was trying in vain to get my own formatter to work that triggers on %Link<x>% . Could you give me hand in doing so?
    I manage to create a static formater but than the link position is fixed and this is not what I need.

    Thanks a lot

     
  • Andrey Semashev

    Andrey Semashev - 2013-03-20

    Basically, it should look along the lines:

    using namespace boost::log;
    void my_formatter(record_view const& rec, formatting_ostream& strm)
    {
        if (value_ref< std::string > message = extract< std::string >("Message", rec))
        {
            std::string formatted = message.get();
            std::vector< std::string > placeholders;
            // parse the message string and store the placeholders in the vector
            for (std::string const& name : placeholders)
            {
                if (value_ref< link > lnk = extract< link >(name, rec))
                {
                    // format the link and replace the placeholders with it in formatted
                }
            }
            strm << formatted;
        }
    }
    sink->set_formatter(&my_formatter);
    

    Also, see here for more examples.

     

Log in to post a comment.