Configuration

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...
 

Detailed Description

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

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

Runtime configuration

The runtime configuration is performed by routing messages to one or more logging targets:
senf::log::FileTarget fileLog ("my.log");
consoleLog.route<senf::log::Debug>();
consoleLog.route<foo::Transactions, foo::SomeClass>(senf::log::Target::REJECT);
consoleLog.route<foo::Transactions, senf::log::IMPORTANT>();
fileLog.route<foo::Transactions>();

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.

Warning
You can only route those messages at runtime which have been compile-time enabled. By default, VERBOSE messages are disabled at compile time. They must be enabled explicitly by setting SENF_LOG_CONF so they can be routed.

Fallback routing

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

Log message timing

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:
// Use senf::scheduler::eventTime() to time log messages
senf::log::timeSource<senf::scheduler::LogTimeSource>();

Macro Definition Documentation

◆ SENF_LOG_CONF

#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).

Definition at line 184 of file Config.hh.

Function Documentation

◆ timeSource() [1/2]

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.

◆ timeSource() [2/2]

template<class Source >
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.