For instance, say you have:
LDBG_ << "user count = " << some_func_taking_a_lot_of_cpu_time();
If LDBG_
is disabled, everything after "LDBG_" is ignored. Thus, some_func_taking_a_lot_of_cpu_time()
will not be called.
First of all, we have 2 concepts:
Note that the logger is a templated class, and the filter is a namespace. I've provided several implementations of the filter concept - you can use them, or define your own.
// Example 1 : 1 filter, 1 logger BOOST_DECLARE_LOG_FILTER(g_log_filter, filter::no_ts ) BOOST_DECLARE_LOG(g_l, logger_type) #define L_ BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() ) // Example 2 : 1 filter (containing a level), several loggers BOOST_DECLARE_LOG_FILTER(g_log_level, level::holder ) BOOST_DECLARE_LOG(g_log_err, logger_type) BOOST_DECLARE_LOG(g_log_app, logger_type) BOOST_DECLARE_LOG(g_log_dbg, logger_type) #define LDBG_ BOOST_LOG_USE_LOG_IF_LEVEL(g_log_dbg(), g_log_level(), debug ) #define LERR_ BOOST_LOG_USE_LOG_IF_LEVEL(g_log_err(), g_log_level(), error ) #define LAPP_ BOOST_LOG_USE_LOG_IF_LEVEL(g_log_app(), g_log_level(), info )
Every time, before anything gets written to the log, the filter is asked if it's enabled. If so, the processing of the message takes place (gathering the message and then writing it). Otherwise, the log message is completely ignored.
What it's enabled is depends on the filter class you use:
is_enabled
function (Example 1, above)is_enabled(level)
, so you can ask if a certain level is enabled (Example 2, above) Thus, logging takes place only if that certain level is enabled (debug
for LDBG_, info
for LAPP_, error
for LERR_)
Depending on your needs, gathering can be complex or not. However, it's completely decoupled from the other steps. Gathering goes hand in hand with macros.
The cool thing is that you decide how the Logging syntax is - depending on how you want to gather the message. All of the below are viable options:
L_("reading " + word); L_ << "this " << " is " << "cool"; L_(dbg) << "happily debugging"; L_(err,"chart")("Cannot load chart")(chart_path);
How you gather your message, depends on how you #define L_ ....
In other words, gathering the message means getting all the message in "one piece", so that it can be written.
See the
operator()
on the writer object.What you choose as the writer object is completely up to you. It can be as simple as this:
// dump message to cout struct write_to_cout { void operator()(const std::string & msg) const { std::cout << msg << std::endl ; } }; typedef logger< gather::ostream_like::return_str<std::string>, write_to_cout> logger_type; BOOST_DECLARE_LOG(g_single_log, logger_type) BOOST_DECLARE_LOG_FILTER(g_filter, filter::no_ts) #define L_ BOOST_LOG_USE_LOG_IF_FILTER(g_single_log, g_filter->is_enabled() ) // usage int i = 100; L_ << "this is " << i << " times cooler than the average log";
You can define your own types of writers. The writer classes that come with this library are in namespace writer
.
At this time, I've defined the concept of writer::format_write - writing using Formatters and Destinations. Simply put, this means formatting the message, and then writing it to destination(s).
For each log, you decide how messages are formatted and to what destinations they are written. Example:
typedef logger_format_write< > logger_type; BOOST_DECLARE_LOG_FILTER(g_log_filter, filter::no_ts ) BOOST_DECLARE_LOG(g_l, logger_type) #define L_ BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() ) // add formatters : [idx] [time] message <enter> g_l()->writer().add_formatter( formatter::idx() ); g_l()->writer().add_formatter( formatter::time("$hh:$mm.$ss ") ); g_l()->writer().add_formatter( formatter::append_newline() ); // add destinations : console, output debug window, and a file called "out.txt" g_l()->writer().add_destination( destination::cout() ); g_l()->writer().add_destination( destination::dbg_window() ); g_l()->writer().add_destination( destination::file("out.txt") ); // usage int i = 1; L_ << "this is so cool " << i++; L_ << "this is so cool again " << i++; // possible output: // [1] 12:32:10 this is so cool 1 // [2] 12:32:10 this is so cool again 2
Remember:
The easy way, use Named Formatters and Destinations
You use a string to specify Formatters, and a string to specify Destinations. Thus, you use the writer::named_write.
First, the examples: example 1, example 2
std::(w)string
. You'll use this when you want a optimize string class. Or, when using tagstypedef boost::logging::named_logger<>::type logger_type;
and typedef your filter class
The manual way
First, the examples: example 1, example 2
std::(w)string
. You'll use this when you want a optimize string class. Or, when using tagsThere are plenty of examples together with code.