Simply put, you need to use macros to make sure objects (logger(s) and filter(s)) :
The problem we want to avoid is using a logger object before it's initialized - this could happen if logging from the constructor of a global/static object.
Using macros makes sure logging happens efficiently. Basically what you want to achieve is something similar to:
if ( is_filter_enabled)
logger.gather_the_message_and_log_it();
#define YOUR_COOL_MACRO_GOOD if ( !is_filter_enabled) ; else logger.gather_the_message_and_log_it();
The above is the correct way, instead of
#define YOUR_COOL_MACRO_BAD if ( is_filter_enabled) logger.gather_the_message_and_log_it();
because of
if ( some_test) YOUR_COOL_MACRO_BAD << "some message "; else whatever();
In this case, whatever()
will be called if some_test
is true, and if is_filter_enabled
is false.
BOOST_DECLARE_LOG(log_name, logger_type)
This declares a log. It should be used in a header file, to declare the log. Note that logger_type
only needs to be a declaration (a typedef
, for instance)
Example:
typedef logger_format_write< > logger_type;
BOOST_DECLARE_LOG(g_l, logger_type)
BOOST_DEFINE_LOG(log_name, logger_type)
This defines a log. It should be used in a source file, to define the log.
Example:
typedef logger_format_write< > logger_type;
...
BOOST_DEFINE_LOG(g_l, logger_type)
BOOST_DEFINE_LOG_WITH_ARGS (log_name, logger_type, args)
This defines a log - and specifies some arguments to be used at its constructed. It should be used in a source file, to define the log.
Example:
typedef logger< default_, destination::file> err_log_type; ... BOOST_DEFINE_LOG_WITH_ARGS( g_log_err(), err_log_type, ("err.txt") )
BOOST_DECLARE_LOG_FILTER(filter_name, filter_type)
This declares a log filter. It should be used in a header file, to declare the log filter.
Example:
BOOST_DECLARE_LOG_FILTER(g_log_filter, filter::no_ts )
BOOST_DEFINE_LOG_FILTER(filter_name, filter_type)
This defines a log filter. It should be used in a source file, to define the log filter.
Example:
BOOST_DEFINE_LOG_FILTER(g_log_filter, filter::no_ts )
BOOST_DEFINE_LOG_FILTER_WITH_ARGS(filter_name, filter_type, args)
This defines a log filter - and specifies some arguments to be used at its constructed. It should be used in a source file, to define the log filter.
Example:
#define L_ BOOST_DEFINE_LOG_FILTER(g_log_filter, filter::no_ts )
BOOST_LOG_USE_LOG_IF_LEVEL(log, level_filter, level )
Example:
BOOST_DECLARE_LOG_FILTER(g_log_level, boost::logging::level::holder )
BOOST_DECLARE_LOG(g_log_err, logger_type)
#define LERR_ BOOST_LOG_USE_LOG_IF_LEVEL(g_log_err(), g_log_level(), error )
See Defining macros to do logging for more details
BOOST_LOG_USE_LOG_IF_FILTER(log, filter_is_enabled)
Example:
#define LERR_ BOOST_LOG_USE_LOG_IF_FILTER(g_log_err(), g_log_filter()->is_enabled() )
See Defining macros to do logging for more details
BOOST_LOG_USE_LOG(l, do_func, is_log_enabled)
Normally you don't use this directly. You use BOOST_LOG_USE_LOG_IF_FILTER or BOOST_LOG_USE_LOG_IF_LEVEL instead.
See Defining macros to do logging for more details
BOOST_LOG_USE_SIMPLE_LOG_IF_FILTER(l, is_log_enabled)
A simple logger is one that uses a simple gather class (FIXME). Example:
struct no_gather { const char * m_msg; no_gather() : m_msg(0) {} const char * msg() const { return m_msg; } void out(const char* msg) { m_msg = msg; } void out(const std::string& msg) { m_msg = msg.c_str(); } }; typedef logger< no_gather, destination::cout > app_log_type; #define LAPP_ BOOST_LOG_USE_SIMPLE_LOG_IF_FILTER(g_log_app(), g_log_filter()->is_enabled() )
See Defining macros to do logging for more details
std::(w)string
BOOST_LOG_FORMAT_MSG( string_class )
You can do this to optimize formatting the message - that is, use a string class optimized for appending and prepending messages (which is basically what formatting is all about).
Example:
BOOST_LOG_FORMAT_MSG( optimize::cache_string_one_str<> )
std::(w)string
BOOST_LOG_DESTINATION_MSG( string_class )
Example:
BOOST_LOG_DESTINATION_MSG( std::string )
Usually you won't need to change this. The destination classes don't change the contets of the string - each class just writes the string to a given destination.
BOOST_LOG_TAG(tag_class)
Adds a tag from the boost::logging::tag namespace. In other words, this is a shortcut for boost::logging::tag::tag_class
. Note that in case the tag_class
has a custom constructor, you need to pass the params as well, after the macro, like shown below.
Example:
#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) )
BOOST_LOG_TAG(tag_level)
Example:
#define LDBG_ BOOST_LOG_USE_LOG_IF_LEVEL(g_log_dbg(), g_log_level(), debug ) .set_tag( BOOST_LOG_TAG_LEVEL(debug) ) #define LERR_ BOOST_LOG_USE_LOG_IF_LEVEL(g_log_dbg(), g_log_level(), error ) .set_tag( BOOST_LOG_TAG_LEVEL(error) )
__FILE__
and __LINE__
will be appended, for each logged message).
BOOST_LOG_TAG_FILELINE
Example:
#define L_ BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() ) .set_tag( BOOST_LOG_TAG_FILELINE)
BOOST_CURRENT_FUNCTION
will be appended, for each logged message).
BOOST_LOG_TAG_FUNCTION
Example:
#define L_ BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() ) .set_tag( BOOST_LOG_TAG_FUNCTION)
include <boost/logging/format.hpp>
in every source file when you want to do logging. This will increase compilation time quite a bit (30 to 50%, in my tests; depending on your application' complexity, this could go higher).Thus, you can choose to:
In the former case, most of the time you won't notice the extra virtual function call, and the compilation time will be faster.
BOOST_LOG_COMPILE_FAST_ON
. The results were not as promising as I had hoped. However, still, when BOOST_LOG_COMPILE_FAST_ON
is on, will compile faster by 30-40%. Noting that this is just an simple example, the results might not be that conclusive. Anyway, here they are:Tested on 16 jan 2008/intel core duo 2.16Ghz machine, 5400Rpm HDD
If you have other results, or results from a big program using Boost Logging, please share them with me. Thanks!
By default, for TSS, we use the internal implementation (no dependency).
The possibilities are:
thread_specific_ptr
classthread_specific_ptr
class.Your class should have this interface:
template <typename T> class my_thread_specific_ptr ;
When defining BOOST_LOG_TSS_USE_CUSTOM, do it like this:
#define BOOST_LOG_TSS_USE_CUSTOM = my_thread_specific_ptr