Classes | |
struct | senf::log::Enabled< Stream, Area, Level > |
Check, if logging is enabled for stream/area/level tuple. More... | |
struct | senf::log::TimeSource |
Log message time source abstract base class. More... | |
struct | senf::log::SystemTimeSource |
Default log message time source. More... | |
Macros | |
#define | SENF_LOG_CONF |
Compile time configuration. More... | |
Functions | |
void | senf::log::timeSource (std::unique_ptr< TimeSource > source) |
Change log message time source. More... | |
template<class Source > | |
void | senf::log::timeSource () |
Change log message time source. More... | |
The logger infrastructure provides for very fine-grained configuration of log messages. There are two parts to this configuration: compile-time configuration and runtime configuration.
Compile-time configuration selects, which log statements will even be compiled. If logging for a certain combination of stream, area and level is disabled at compile time, no code will be generated for any such disabled log statement. This type of configuration is done using SENF_LOG_CONF.
Runtime configuration on the other hand deals with routing all those messages, which are enabled at compile time to the logging targets. If a message is not routed, it will be discarded. This allows to additionally disable messages at run-time. Message routing is managed via the ::Target interface.
Compile time configuration is set on the compiler command line:
g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Debug),(_),DISABLED )) (( (senf)(log)(Debug),(foo)(SomeClass),VERBOSE )) (( (_),(_),NOTICE ))" ...
The value is relatively complex; It's a Boost.Preprocessor style sequence of tuples, of which the first and second elements are again sequences. What this boils down to, is that it allows to configure compile time logging limits based on stream and optional area.
The above example disables all debug logging by setting the default log limit for all areas on the senf::log::Debug
stream to DISABLED
. It enables debug logging only within the foo::SomeClass
area, where it is set to VERBOSE
. Lastly, the global compile time limit is set to NOTICE
.
There are two standard uses for this configuration: Either to disable most logging in final builds by changing the compile time limit to something like senf::log::IMPORTANT or to enable senf::log::VERBOSE messages for some area:
Disable debug logging below 'IMPORTANT' level
g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Debug), (_), IMPORTANT ))"
Or enable verbose messages for the 'some::Area' area
g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Verbose), (some)(Area), VERBOSE ))"
All the entries specified via \c SENF_LOG_CONF are applied in a fixed order: \li First the entries which have both a stream and an area specified are checked \li next all entries with area but no stream given are checked \li followed by all entries with a given stream but no area \li and lastly if no match was found until now, a generic entry without stream and area is checked \li if no matching entry is found, the default compile time limit of the stream is used So an area specification has precedence over a stream specification. \warning Enabling a message at compile time does \e not ensure, the message is shown. You additionally need to \e route the message (see next chapter). This is especially true for \c VERBOSE messages, which are default disabled at runtime. \see \ref SENF_LOG_CONF
The runtime configuration is performed by routing messages to one or more logging targets:
Here we see an already relatively complex setup: All debug messages (that is, those, which are not disabled at compile time) are routed to the console. We also route important transactions to the console except transactions from the foo::SomeClass
area. The fileLog
simply receives all transaction log messages.
The routing statements are processed by the targets in order, the first matching rule will decide a log messages fate for that target.
VERBOSE
messages are disabled at compile time. They must be enabled explicitly by setting SENF_LOG_CONF
so they can be routed.There are two cases, where this setup may lead to inadvertently lost log messages: \li When using a library which does internally use the Logger but not initializing the logger in your application. \li When log messages are created during initialization of static objects. Since no route is set up in these cases, the messages will be dropped. To counter this problem, the logger is initially in <em>fallback routing</em> state. If any log message arrives in this state, the message will be logged to the console if it is above the default runtime limit of it's stream. The first routing statement on any target will take the logger out of this state and normal routing will take place. \see \ref senf::log::Target
One auxiliary aspect of logging is message timing. Each message is stamped with a time-stamp giving the exact time the message was created. How the current date/time value is created may be changed by setting a \e TimeSource. A TimeSource is an instance derived from senf::log::TimeSource which will return the current universal time (UTC) when called. By default, the logging library will call gettimeofday() for each log message. To change the time source, just pass the new class or instance to senf::log::timeSource:
#define SENF_LOG_CONF |
Compile time configuration.
This define symbol sets the compile time logger configuration. This symbol should normally be set on the compiler command line.
The formal syntax of this option is:
conf | ::= element element* |
element | ::= (( optional_stream , optional_area , level )) |
optional_stream | ::= (_) | scope_seq |
optional_area | ::= (_) | scope_seq |
level | ::= VERBOSE | NOTICE | MESSAGE | IMPORTANT | CRITICAL | DISABLED |
scope_seq | ::= scope scope* |
scope | ::= ( name ) |
name | ::= arbitrary C++ identifier |
SENF_LOG_CONF is a Boost.Preprocessor style sequence of 3-tuples.
The first tuple element optional_stream specifies the stream to match. If this is (_)
, the entry will match any stream.
The next tuple element, optional_area optionally restricts the entry to match only the given area. If set to (_)
, the area is left unrestricted.
The last tuple element level defines the compile time log level. Messages with a level below this are discarded at compile time.
Both optional_stream and optional_area are given as a scope_seq. A scope sequence is a fully qualified C++ identifier placed into a sequence: foo::bar::baz
is represented by (foo)(bar)(baz)
.
void senf::log::timeSource | ( | std::unique_ptr< TimeSource > | source | ) |
Change log message time source.
Set the log message time source to source. The logging library will take ownership of source and will take care to free it, if necessary.
Since the time source class will in almost all cases be default constructible, see the template overload for a simpler interface.
void senf::log::timeSource | ( | ) |
Change log message time source.
Set the log message time source to (an instance of) Source. Source must be default constructible, otherwise use the non-template senf::log::timeSource() overload.