Needful Software

Boost.Log

Introduction

As the name implies the Boost.Log[1] library provides a logging framework.

Trivial Logging Example

Boost.Log provides a rich framework for logging. However the complete framework comes with some degree of complexity that may not be needed for simple cases. For those cases it provides a simple implementation of a logger based on the generic logging framework. That implementation is called "trivial" and is defined in boost/log/trivial.hpp. This is what we will use in our first examples.

In this example we use the BOOST_LOG_TRIVIAL macro to write log lines to the console. The macro takes a single argument which is the severity of the event being logged and returns an output stream. Writing to the log is therefore very similar to writing to std::cout. The full example is available from our GitHub repository: BoostTutorials/Log/Log1

 File: main.cpp
#include <boost/log/trivial.hpp>

int main(int argc, char* argv[])
{
    BOOST_LOG_TRIVIAL(trace) << "Severity: trace";
    BOOST_LOG_TRIVIAL(debug) << "Severity: debug";
    BOOST_LOG_TRIVIAL(info) << "Severity: info";
    BOOST_LOG_TRIVIAL(warning) << "Severity: warning";
    BOOST_LOG_TRIVIAL(error) << "Severity: error";
    BOOST_LOG_TRIVIAL(fatal) << "Severity: fatal";

    return 0;
}

The severity levels that can be passed in to the macro are defined by the boost::log::trivial::severity_level enum which is shown below.

 Code: boost::log::trivial::severity_level enum
enum severity_level
{
    trace,
    debug,
    info,
    warning,
    error,
    fatal
};

The code above produces the following output.

 Console output
[2017-12-27 20:54:14.192152] [0x0001f1b8] [trace]   Severity: trace
[2017-12-27 20:54:14.194152] [0x0001f1b8] [debug]   Severity: debug
[2017-12-27 20:54:14.194152] [0x0001f1b8] [info]    Severity: info
[2017-12-27 20:54:14.194152] [0x0001f1b8] [warning] Severity: warning
[2017-12-27 20:54:14.194152] [0x0001f1b8] [error]   Severity: error
[2017-12-27 20:54:14.194152] [0x0001f1b8] [fatal]   Severity: fatal
Press any key to continue . . .

The output illustrates the format of the log produced by the trivial logger: a timestamp, the thread ID, the severity and finally the actual message.

Sinks

In the terminology of Boost.Log a sink is somewhere log data can be written. In the previous example we used the default sink which displays the data to the console in a fixed format. The default sink is only used if no other sink has been setup.

In the next example we will show how to send the log data to a file.

Logging to a File

In this example we will use the function boost::log::add_file_log to setup a file sink. Because we setup a sink explicitly the default sink is disabled and the logging macros will use the sink we setup. The full example is available from our GitHub repository: BoostTutorials/Log/FileLog1

 File: main.cpp
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/file.hpp>

int main(int argc, char* argv[])
{
    boost::log::add_file_log("sample.log");

    BOOST_LOG_TRIVIAL(error) << "Severity: error";

    return 0;
}

The code above produces the following file.

 File: sample.log
Severity: error

Multithreaded Logging

This example is used to show that the trivial logger works equally well when used from multiple threads. We will count from 0 to 4 in 3 concurrent threads (the main thread and 2 child threads). The full example is available from our GitHub repository: BoostTutorials/Log/LogMultithreaded1

The code below uses boost::thread to create new threads. A tutorial for boost::thread is available here.

 File: main.cpp
#include <boost/log/trivial.hpp>
#include <boost/thread/thread.hpp>

// A function that counts from 0 to 4 and sleeps for 1ms between each
// number. That time was chosen because it produces good interleaving 
// on my computer.
void CountSlowly()
{
    BOOST_LOG_TRIVIAL(info) << "Thread id: " << boost::this_thread::get_id();
    for (int i = 0; i < 5; ++i)
    {
        BOOST_LOG_TRIVIAL(info) << "i: " << i;

        boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
    }
}

int main(int argc, char* argv[])
{
    BOOST_LOG_TRIVIAL(info) << "Main thread id: " << boost::this_thread::get_id();

    // Create and run 2 threads that execute CountSlowly()
    boost::thread thread1(CountSlowly);
    boost::thread thread2(CountSlowly);

    // The main thread also executes CountSlowly()
    CountSlowly();

    // Wait for the launched threads to complete
    thread1.join();
    thread2.join();

    return 0;
}

This produces the following output. The thread ID can be used to distinguish between the log lines produced by each thread.

 Console output
[2017-12-28 17:25:42.226867] [0x00023534] [info]    Main thread id: 23534
[2017-12-28 17:25:42.228871] [0x00023534] [info]    Thread id: 23534
[2017-12-28 17:25:42.228871] [0x00023534] [info]    i: 0
[2017-12-28 17:25:42.229868] [0x00028a44] [info]    Thread id: 28a44
[2017-12-28 17:25:42.229868] [0x000115bc] [info]    Thread id: 115bc
[2017-12-28 17:25:42.229868] [0x00028a44] [info]    i: 0
[2017-12-28 17:25:42.229868] [0x000115bc] [info]    i: 0
[2017-12-28 17:25:42.230881] [0x00028a44] [info]    i: 1
[2017-12-28 17:25:42.230881] [0x00023534] [info]    i: 1
[2017-12-28 17:25:42.230881] [0x000115bc] [info]    i: 1
[2017-12-28 17:25:42.231887] [0x00028a44] [info]    i: 2
[2017-12-28 17:25:42.231887] [0x00023534] [info]    i: 2
[2017-12-28 17:25:42.231887] [0x000115bc] [info]    i: 2
[2017-12-28 17:25:42.232887] [0x00023534] [info]    i: 3
[2017-12-28 17:25:42.232887] [0x000115bc] [info]    i: 3
[2017-12-28 17:25:42.232887] [0x00028a44] [info]    i: 3
[2017-12-28 17:25:42.234887] [0x000115bc] [info]    i: 4
[2017-12-28 17:25:42.234887] [0x00023534] [info]    i: 4
[2017-12-28 17:25:42.234887] [0x00028a44] [info]    i: 4
Press any key to continue . . .

References

  1. Boost.Log: official documentation (boost.org)