boost::logging::tag Namespace Reference

Allows you to use tags (extra information about the context of the logged message: file/line, function name, thread id, etc.), and log this information as well. More...


Classes

struct  holder
 Holds up to 10 tags. More...
struct  file_line
 tag that holds file/line context information More...
struct  function
 tag that holds function name context information More...
struct  level
 tag that holds the log level context information More...
struct  time
 tag that holds the current time context information More...
struct  module
 tag that holds module context information (note: you need to specify the module yourself) More...
struct  thread_id
 tag that holds thread id context information More...
struct  high_precision_time
 tag that holds the current time (with high precision) context information More...


Detailed Description

Allows you to use tags (extra information about the context of the logged message: file/line, function name, thread id, etc.), and log this information as well.

Do you need tags?

First of all, note that the easiest way to log some extra context is to simply append it, when definining your macro:

#define LDBG_ BOOST_LOG_USE_LOG_IF_LEVEL(g_l(), g_log_level(), debug ) << __FILE__ << ":" << __LINE__ << " [dbg] "

In the above case, you appended file & line, and the level of the logged message. Usage is just the same:

std::string hello = "hello", world = "world";
LAPP_ << hello << ", " << world;

The output could look like:

my_cool_sample:234 [dbg] hello, world

I can see a few issues with the above

If you're ok with the above issues, no need to delve into tags. You can dump context like shown above, and be fine with it.

Otherwise, welcome to the world of tags!

Tags - explained

#include <boost/logging/format_fwd.hpp>

Tag classes

Each single context information you need to hold, is identified by a tag class. Tag classes are always found in the boost::logging::tag namespace.

A tag class is deadly simple. Here are a few examples:

struct file_line {
    file_line(const char * val = "") : val(val) {}
    const char * val;
};

struct time {
    time() : val( ::time(0) ) {}
    ::time_t val;
};

They only allow holding the context, and making sure you can get to it - when doing formatting. You can of course add your own tag clases.

Tag Holder - holding the tags

Now, you have to decide what tags you need. You will use templated class tag::holder:

You will replace your old BOOST_LOG_FORMAT_MSG(string_class) usage, with tags. In case you don't have a BOOST_LOG_FORMAT_MSG in your application, the string_class is std::(w)string.

// old 
BOOST_LOG_FORMAT_MSG( optimize::cache_string_one_str<> )

// new - use tags
//
//       In our case, time, file/line, function name
typedef tag::holder< optimize::cache_string_one_str<>, tag::time, tag::file_line, tag::function> string;
BOOST_LOG_FORMAT_MSG( string )

Adding tags to your LOG macros

Some tag classes compute their context automatically (for instance, the tag::time class). However, some tag classes need you to manually specify it, in your LOG macros. This is the case for file/line, function, level, etc.

In your LOG macros, you need to append the tags like this:

Examples:

// add file/line and function tags
#define L_ BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() ) .set_tag(BOOST_LOG_TAG_FILELINE) .set_tag(BOOST_LOG_TAG_FUNCTION)

// add function and level
#define LDBG_ BOOST_LOG_USE_LOG_IF_LEVEL(g_log_dbg(), g_log_level(), debug ) .set_tag(BOOST_LOG_TAG_FUNCTION) .set_tag( BOOST_LOG_TAG_LEVEL(debug) )

// add module information - you specify the module name whe using the L_ macro. Example:
// L_("chart") << "Initializing environment";
#define L_(module_name) BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() ) .set_tag( BOOST_LOG_TAG(module)(module_name) )

Processing the tags

Now, you're ready to process these tags - where you're specifying your formatters and/or destinations, add the tag formatters that will process your tags. Example:

#include <boost/logging/format/formatter/tags.hpp>
...

g_l()->writer().add_formatter( formatter::idx() );
g_l()->writer().add_formatter( formatter::append_newline() );

// formatters to add the file/line and level
g_l()->writer().add_formatter( formatter::tag::file_line() );
g_l()->writer().add_formatter( formatter::tag::level() );

g_l()->writer().add_destination( destination::file("out.txt") );
g_l()->writer().add_destination( destination::cout() );
g_l()->writer().add_destination( destination::dbg_window() );

Note that the library comes with default formatters for each tag class. However, you can create your own formatter class, for a given tag class.

The formatters that come with the library, have the same name as the tag class itself, only that they're in the formatter::tag namespace.

Examples:

When adding the formatters, don't forget to:

#include <boost/logging/format/formatter/tags.hpp>

Example using Tags

This usage:

Optimizations:

In this example, all output will be written to the console, debug window, and "out.txt" file. The output can look like:

logging\samples\scenarios\using_tags.cpp:94 [T7204] [1] 14:55 this is so cool 1
logging\samples\scenarios\using_tags.cpp:95 [T7204] [2] 14:55 this is so cool again 2

#include <boost/logging/format_fwd.hpp>

namespace bl = boost::logging;
typedef bl::tag::holder< bl::optimize::cache_string_one_str<>, bl::tag::file_line, bl::tag::thread_id, bl::tag::time> log_string;
BOOST_LOG_FORMAT_MSG( log_string )


#include <boost/logging/format_ts.hpp>
#include <boost/logging/format/formatter/tags.hpp>
#include <boost/logging/format/formatter/named_spacer.hpp>

using namespace boost::logging;

using namespace boost::logging::scenario::usage;
typedef use<
        //  the filter is always accurate (but slow)
        filter_::change::always_accurate, 
        //  filter does not use levels
        filter_::level::no_levels, 
        // the logger is initialized once, when only one thread is running
        logger_::change::set_once_when_one_thread, 
        // the logger favors speed (on a dedicated thread)
        logger_::favor::speed> finder;

BOOST_DECLARE_LOG_FILTER(g_log_filter, finder::filter ) 
BOOST_DECLARE_LOG(g_l, finder::logger) 

#define L_ BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() ) .set_tag( BOOST_LOG_TAG_FILELINE)

BOOST_DEFINE_LOG_FILTER(g_log_filter, finder::filter ) 
BOOST_DEFINE_LOG(g_l, finder::logger) 


void using_tags_example() {
    //         add formatters and destinations
    //         That is, how the message is to be formatted and where should it be written to

    g_l()->writer().add_formatter( formatter::named_spacer( "%fileline% [T%thread_id%] [%idx%] %time%" )
        .add( "time", formatter::tag::time("$mm:$ss ") )                // time tag
        .add( "idx", formatter::idx() )                            
        .add( "thread_id", formatter::tag::thread_id() )                // thread_id tag
        .add( "fileline", formatter::tag::file_line() ) );              // file/line tag

    g_l()->writer().add_formatter( formatter::append_newline() );     
    g_l()->writer().add_destination( destination::cout() );
    g_l()->writer().add_destination( destination::file("out.txt") );
    g_l()->mark_as_initialized();

    int i = 1;
    L_ << "this is so cool " << i++;
    L_ << "this is so cool again " << i++;
}




int main() {
    using_tags_example();
}


// End of file

That's it, enjoy!



Copyright John Torjo © 2007
Have a question/ suggestion/ comment? Send me feedback