C++ Boost

Loglite

Tutorial

Boost Libraries Index


Tutorial

First, we assume boost is installed and compiled correctly, as descriped there. Boost.Date_Time, Boost.Shared_Ptr and eventually Boost.Thread must be compiled.

Hello World

Here is the Hello World! example:
#include <iostream>
#include <fstream>
#include <logging.hpp>

int main()
{
  BOOST_LOG_INIT( (boost::logging::trace >> boost::logging::eol) ); //log format
   
  boost::logging::sink sink_cout(&std::cout);
  boost::logging::sink sink_file(new std::ofstream("./output.log"));
  sink_cout.attach_qualifier(boost::logging::log);
  sink_file.attach_qualifier(boost::logging::log);
  
  BOOST_LOG_ADD_OUTPUT_STREAM(sink_cout);
  BOOST_LOG_ADD_OUTPUT_STREAM(sink_file);

  BOOST_LOG_(1, "Hello World!");
  return 0;
}
    
  The macro BOOST_LOG_INIT initializes the logger object which is a static member used as a singleton. This is a limitation of Boost.Logging. Only one object can be used for logging through a program, but this is the cost of simplicity. It will allow us to use the macro BOOST_LOG_ anywhere in our source code to trace effortlessly.

   - The only argument of BOOST_LOG_INIT is the format used to produce the log. This format is defined using element of log. Basically here, it tells the logguer to first display the message of the log (what we call the trace) and then append an end-of-line. You can refere to this page for a complete reference of log elements.

We, then, define sinks. A sink is an object attached to the logger that filters and eventually print out traces. It will allow us to have different format, different log level for different output. In our example here, we have 2 sinks. A sink that is connected to the standard output (std::cout) and one connected to an ofstream (itself outputting to a file called output.log). Then we need to specify which kind of trace is going through our sink. Here, for both sink, we are accepting onlu logging::log. There is different qualifier (log, warning, error, etc...). Each are for specific usage. You can define more by yourself if you need to, just look at logging.hpp.

  The macro BOOST_LOG_ADD_OUTPUT_STERAM is connecting the sink to the logger. By default, the sink will use the last format added to the logger. Here, the one define in BOOST_LOG_INIT. If you want to specify a particular format to a sink, please refer to the next examples.

  The macro BOOST_LOG_ is used to trace. It can be used anywhere as soon as BOOST_LOG_INIT is called and wherever you include logging.hpp. Other macro exists to produce traces, they are described in the reference.
   - The first argument specifies the log level.
   - The second argument specifies the trace itself. This trace can be a stream of strings and so can easily be used to trace anything that can be inserted into a std::stringstream.

A real trace

#include <fstream>
#include <logging.hpp>

int infinite_loop()
{
  BOOST_LOG_L1("oops...");
  while (1) ;
}

int foo()
{
  BOOST_LOG_(1, "foo called");
  return 7;
}

int main(int argc, char **argv)
{
  BOOST_LOG_INIT(("[" >> boost::logging::mask >> "],"
                      >> boost::logging::filename >> "("
                      >> boost::logging::line >> "),"
                      >> boost::logging::time >> ","
                      >> boost::logging::trace
                      >> boost::logging::eol)); // log format

  boost::logging::sink s1(new std::ofstream("./output.log"), BOOST_LOG_MASK_LEVEL_2);
  s1.attach_qualifier(boost::logging::log);
  BOOST_LOG_ADD_OUTPUT_STREAM(s1);

  boost::logging::sink s2(&std::cout, BOOST_LOG_MASK_LEVEL_2);
  s2.attach_qualifier(boost::logging::log);
  BOOST_LOG_ADD_OUTPUT_STREAM(s2);

  BOOST_LOG_(BOOST_LOG_LEVEL_1, "something");
  BOOST_LOG_(BOOST_LOG_LEVEL_2, "something else");
  BOOST_LOG_(BOOST_LOG_LEVEL_3, "If you evaluate me you die!" << infinite_loop());
  char you_want[256] = "you want";
  BOOST_LOG_(BOOST_LOG_LEVEL_1, "Let's say " << you_want << " to display " << 2);
  BOOST_LOG_(BOOST_LOG_LEVEL_1, "foo will be evaluated: " << foo());
  return 0;
}
    
Output is:
[1],/home/michaudjd/c++/loglite/test/logging_test_macro.cpp(43),2008-01-05 06:35:35.694131,something
[2],/home/michaudjd/c++/loglite/test/logging_test_macro.cpp(44),2008-01-05 06:35:35.701461,something else
[1],/home/michaudjd/c++/loglite/test/logging_test_macro.cpp(47),2008-01-05 06:35:35.703590,Let's say you want to display 2
[1],/home/michaudjd/c++/loglite/test/logging_test_macro.cpp(22),2008-01-05 06:35:35.705387,foo called
[1],/home/michaudjd/c++/loglite/test/logging_test_macro.cpp(48),2008-01-05 06:35:35.706065,foo will be evaluated: 7
    
  Several feature of loglite are presented here. First, we introduce the log mask. This concept allow us to have different level of log message. Some more important than others. Thanks to the mask, the logger in filtering what is logged or not. If you define a mask level of 2 for your sink, as for the fiel output.log in the example. Then, an trace with a superior mask level (so less important) will be ignored. Ignored means that it's not even evaluated. Here, the function infinite_loop is not called, because the level is too high.

Produce XML

#include <boost/bind.hpp>
#include <fstream>
#include <boost/logging.hpp>

int main(int argc, char **argv)
{
  BOOST_LOG_INIT(("\t<log>" >> boost::logging::eol >>
      "\t\t<level>" >> boost::logging::level >> "</level>" >> boost::logging::eol >>
      "\t\t<filename>" >> boost::logging::filename >> "</filename>" >> boost::logging::eol >>
      "\t\t<line>" >> boost::logging::line >> "</line>" >> boost::logging::eol >>
      "\t\t<time>" >> boost::logging::time >> "</time>" >> boost::logging::eol >>
      "\t\t<trace>" >> boost::logging::eol >> "\t\t\t" >>
        boost::logging::trace >> boost::logging::eol >>
      "\t\t</trace>" >> boost::logging::eol >>
    "\t</log>" >> boost::logging::eol),
    2); // Max log level
  
  sink sink_file(new std::ofstream("./output.xml"), BOOST_LOG_MASK_LEVEL_2);
  sink_file.attach_qualifier(boost::logging::log);
  BOOST_LOG_ADD_OUTPUT_STREAM(sink_file);

  sink sink_cout(&std::cout, BOOST_LOG_MASK_LEVEL_2);
  sink_cout.attach_qualifier(boost::logging::log);
  BOOST_LOG_ADD_OUTPUT_STREAM(sink_cout);

  boost::gregorian::date d(boost::gregorian::day_clock::local_day());
  std::string date = boost::gregorian::to_iso_extended_string(d);

  BOOST_LOG_UNFORMATTED(1, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl);
  BOOST_LOG_UNFORMATTED(1, "<log_session date=\"" << date << "\">" << std::endl);

  BOOST_LOG_(1, "Strange women lying in ponds distributing swords");
  BOOST_LOG_(1, "is no basis for a system of government");
  BOOST_LOG_(1, "Supreme executive power derives from a mandate of the masses");
  BOOST_LOG_(1, "not from some farcical aquatic ceremony!");

  BOOST_LOG_UNFORMATTED(1, "</log_session>");
  
  return 0;
}
    
    
Output:
<?xml version="1.0" encoding="UTF-8"?>
<log_session date="2007-03-31">
	<log>
		<level>1</level>
		<filename>logging_test_xml_output.cpp</filename>
		<line>27</line>
		<time>2007-Mar-31 21:19:38.655552</time>
		<trace>
			Strange women lying in ponds distributing swords
		</trace>
	</log>
	<log>
		<level>1</level>
		<filename>logging_test_xml_output.cpp</filename>
		<line>28</line>
		<time>2007-Mar-31 21:19:38.655552</time>
		<trace>
			is no basis for a system of government
		</trace>
	</log>
	<log>
		<level>1</level>
		<filename>logging_test_xml_output.cpp</filename>
		<line>29</line>
		<time>2007-Mar-31 21:19:38.665566</time>
		<trace>
			Supreme executive power derives from a mandate of the masses
		</trace>
	</log>
	<log>
		<level>1</level>
		<filename>logging_test_xml_output.cpp</filename>
		<line>30</line>
		<time>2007-Mar-31 21:19:38.665566</time>
		<trace>
			not from some farcical aquatic ceremony!
		</trace>
	</log>
</log_session>    
    
Here loglite produces xml output. Not that the header and footer are produced using the macro BOOST_LOG_UNFORMATTED which ignores the format attached to the sink.

Different sink with different formats and qualifiers

#include <fstream>
#include <logging.hpp>

using namespace boost::logging;
namespace bl = boost::logging;

void overheat(int d)
{
  BOOST_LOG(2, bl::log, "overheat called");
  BOOST_LOG(1, bl::warning, "Warning: Tube overheat! Shutdown system immediatly");
  BOOST_LOG(1, bl::error, "ERROR: tube overheat: " << d << "d C. Shutdown should follow");
}

int do_something()
{
  BOOST_LOG(2, bl::log, "do_something called");
  BOOST_LOG(2, bl::notice, "do_something is performing some fancy processing (useless log don't you think?)");

  return 7;
}

int main(int argc, char **argv)
{
  boost::logging::logger_p l = boost::logging::logger::get_instance();

  boost::logging::format display_format(boost::logging::trace >> boost::logging::eol);
  boost::logging::format file_format("[" >> boost::logging::mask >> "],"
                                         >> boost::logging::filename >> "("
                                         >> boost::logging::line >> "),"
                                         >> boost::logging::time >> ","
                                         >> boost::logging::trace
                                         >> boost::logging::eol); // log format
  l->add_format(display_format);
  l->add_format(file_format);


  boost::logging::sink file_sink(new std::ofstream("./output.log"), BOOST_LOG_MASK_LEVEL_3);
  file_sink.attach_qualifier(bl::log);
  file_sink.attach_qualifier(bl::error);
  l->add_sink(file_sink, file_format);

  boost::logging::sink display_sink(&std::cout, BOOST_LOG_MASK_LEVEL_1);
  display_sink.attach_qualifier(bl::notice);
  display_sink.attach_qualifier(bl::warning);
  l->add_sink(display_sink, display_format);

  BOOST_LOG(BOOST_LOG_LEVEL_1, bl::log, "Application starting");
  BOOST_LOG(BOOST_LOG_LEVEL_1, bl::notice, "Application version 1.0.3 - Copyright(2007) World Company");

  BOOST_LOG(BOOST_LOG_LEVEL_1, bl::log, "do_something returned: " << do_something());
  overheat(87);
  return 0;
}

  In this example, we are using Loglite to display error and warning message on the screen with almost no formatting (only the addition of an end of line) but also output more detail debugging message to an output file, with a more complex format.   Also, the terminal is receiving only warning and notice trace when the output debugging file received only log and error message.

Define log element format

#include <fstream>
#include <logging.hpp>

namespace bl = boost::logging;

int main(int argc, char **argv)
{
  BOOST_LOG_INIT((" L" >> bl::mask >> ","
                       >> (*new bl::filename_element(bl::filename_element::filename_only)) >> "("
                       >> bl::line >> "),"
                       >> (*new bl::date_element("%d/%m/%Y")) >> " "
                       >> (*new bl::time_element("%H:%M:%S%F")) >> ","
                       >> bl::trace
                       >> bl::eol)); // log format

  bl::sink s1(&std::cout, BOOST_LOG_MASK_LEVEL_2);
  s1.attach_qualifier(bl::log);
  BOOST_LOG_ADD_OUTPUT_STREAM(s1);

  BOOST_LOG_(BOOST_LOG_LEVEL_1, "Hello, I'm H.G. Pennypacker");
  BOOST_LOG_(BOOST_LOG_LEVEL_2, "wealthy american industrialist");
  BOOST_LOG_(BOOST_LOG_LEVEL_2, "philantropist and ...");
  BOOST_LOG_(BOOST_LOG_LEVEL_1, "bicyclist!");

  return 0;
}
    
  Most log elements can be customize to match your requirements. In this example, we choose to display the filename without its path, and we also have customize the date and time format. For the format definition for date and time, please refer to Boost.DateTime documentation.

Revised 31 March 2007 

© Copyright Jean-Daniel Michaud 2007

Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)