Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

This is the documentation for an old version of Boost. Click here to view this page for the latest version.
PrevUpHomeNext

Creating loggers and writing logs

Dedicated logger objects

Now that we have defined where and how the log is to be stored, it's time to see how we emit log records. In order to be able to make log records one has to create a logging source first. This would be a logger object in our case and it is as simple as that:

src::logger lg;
[Note] Note

A mindful reader could have noticed that we did not create any loggers when we tried trivial logging. In that case the logger is provided by the library and is used behind the scenes.

Unlike sinks, sources need not be registered anywhere since they interact directly with the logging core. Also note that there are two versions of loggers provided by the library: the thread-safe ones and the non-thread-safe ones. For the non-thread-safe loggers it is safe for different threads to write logs through different instances of loggers and thus there should be a separate logger for each thread that writes logs. The thread-safe counterparts can be accessed from different threads concurrently, but this will involve locking and may slow things down in case of intense contention. The thread-safe logger types have the _mt suffix in their name.

Regardless of the thread safety, all loggers provided by the library are default and copy-constructible and support swapping, so there should be no problem in making a logger a member of your class. As you will see later, such approach can give you additional benefits.

The library provides a number of loggers with different features, such as severity and channel support. These features can be combined with each other in order to construct more complex loggers. See here for more details.

Global logger objects

In case you cannot put a logger into your class (suppose you don't have one), the library provides a way of declaring global loggers like this:

BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::logger_mt)

Here my_logger is a user-defined tag name that will be used later to retrieve the logger instance and logger_mt is the logger type. Any logger type provided by the library or defined by the user can participate in such declaration. However, since the logger will have a single instance, you will normally want to use thread-safe loggers in a multithreaded application as global ones.

[Tip] Tip

There are other macros for more sophisticated cases available. The detailed description is in this section.

Later on you can acquire the logger like this:

src::logger_mt& lg = my_logger::get();

Then, lg will refer to the one and only instance of the logger throughout the application, even if the application consists of multiple modules. The get function itself is thread-safe, so there is no need in additional synchronization around it.

Writing logs

No matter what kind of logger you use (class member or global, thread-safe or not), to write a log record into a logger you can write something like this:

logging::record rec = lg.open_record();
if (rec)
{
    logging::record_ostream strm(rec);
    strm << "Hello, World!";
    strm.flush();
    lg.push_record(boost::move(rec));
}

Here the open_record function call determines if the record to be constructed is going to be consumed by at least one sink. Filtering is applied at this stage. If the record is to be consumed, the function returns a valid record object, and one can fill in the record message string. After that the record processing can be completed with the call to push_record.

Of course, the above syntax can easily be wrapped in a macro and, in fact, users are encouraged to write their own macros instead of using the C++ logger interface directly. The log record above can be written like this:

BOOST_LOG(lg) << "Hello, World!";

Looks a bit shorter, doesn't it? The BOOST_LOG macro, along with other similar ones, is defined by the library. It automatically provides a standard library-like output stream in order to format the message with ordinary insertion expressions. Having all that code written, compiled and executed you should be able to see the "Hello, World!" record in the "sample.log" file. You will find the full code of this section here.


PrevUpHomeNext