// $Id$
//
-// Copyright (C) 2007
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Copyright (C) 2007
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
targets at the same time. To allow concise usage of the library, a utility to define logging
defaults for any scope is provided.
- An important basic concept of the library is, that most of the macros take a variable number of
- arguments. Since this is not supported in the needed manner by the C++ preprocessor, the
- arguments are encoded into a <a
- href="http://www.boost.org/libs/preprocessor/doc/index.html">Boost.Preprocessor</a> like
- sequence:
+ \see
+ \ref logging \n
+ \ref config \n
+ \ref targets \n
+ \ref loglevels
+
+ \section logging_concepts Concepts
+
+ Log messages are arbitrarily created throughout the code using simple log statements (which are
+ macros). Besides the log message itself, every log message is labeled with additional
+ information: The \e stream, the \e area and a log \e level. If the message is not compile-time
+ disabled, the message is then directed to one or several log \e targets.
+
+ A \e stream combines log messages with a single purpose: Debug messages, access logging and so
+ on. Any number of streams may be defined. There is one predefined default stream called \c
+ senf::log::Debug. (see: \ref SENF_LOG_DEFINE_STREAM)
+
+ The \e area gives information about the source location of the message. Areas may be defined and
+ assigned arbitrarily but should be used to label messages from a single class or subsystem. It
+ is possible to reuse a class as it's own area tag, which is often desireable. There is a
+ default area \c senf::log::DefaultArea which is used, when no other area is assigned. (see: \ref
+ SENF_LOG_DEFINE_AREA, \ref SENF_LOG_CLASS_AREA)
+
+ The log \e level gives information on the importance of the message. The list of log-levels is
+ fixed. (see: \ref loglevels)
+
+ Depending on their the \e stream, \e area and \e level information, log messages can be enabled
+ or disabled at \e compile time. Messages disabled at compile time should not generate any
+ code. (see: \ref SENF_LOG_CONF)
+
+ \attention The default log stream senf::log::Debug has senf::log::VERBOSE messages
+ <em>disabled</em> at compile time. senf::log::VERBOSE message will therefore only appear,
+ if you explictly enable the messages for the area in question using (here for the area
+ <code>some::Area</code>)
+ <pre>
+ g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Debug), (some)(Area), VERBOSE ))"
+ </pre>
+ in addition to routing the messages at runtime. For more, see \ref config.
+
+ To be of any use, the log messages have to be written somewhere. This is the responsibility of
+ any number of \e targets. A \e target receives messages and using it's routing information
+ decides, wether the message is output or not. A message may be routed to multiple targets
+ simultaneously or may not be output by any target at all. (see: \ref targets)
+
+ \section logging_tutorial Tutorial introduction
+
+ Using the logging library mostly concerns using \ref SENF_LOG statements in your code. There are
+ some other helpers used to simplify specifying parameters.
\code
- SENF_LOG( (senf::log::Debug)(senf::log::NOTICE)(FroblizerArea)("The log message") );
- \endcode
-
- The last sequence element always is the log message. Before that we have a number of log
- parameters <i>in arbitrary order</i>. Since giving all the parameters in every log message is to
- verbose, there are two helpful constructs to reduce the verbosity. Using \ref
- SENF_LOG_DEFAULT_STREAM, \ref SENF_LOG_DEFAULT_AREA and \ref SENF_LOG_DEFAULT_LEVEL it is
- possible to define the default logging parameters to be used within a given scope. Using \ref
- SENF_LOG_DEF_ALIAS you can define an alias (which is a scoped symbol) as an arbitrary
- combination of parameters.
+ namespace foo {
- \code
- SENF_LOG_DEF_STREAM( userLog, senf::log::MESSAGE, senf::log::MESSAGE );
+ // Define a new log stream with default level, runtime limit and compile time limit
+ // set to senf::log::MESSAGE
+ SENF_LOG_DEFINE_STREAM( UserLog, senf::log::MESSAGE, senf::log::MESSAGE, senf::log::MESSAGE );
- class Froblizer
- {
- // Define a new log area
- SENF_LOG_DEF_AREA(FroblizerArea);
+ class Froblizer
+ {
+ // Define a log area which will automatically be used by all members of this class.
+ // This is a combination of SENF_LOG_DEFINE_AREA and SENF_LOG_DEFAULT_AREA.
+ SENF_LOG_CLASS_AREA();
- // Set default log parameters for this scope
- SENF_LOG_DEFAULTS((senf::log::Debug)(senf::log::NOTICE)(FroblizerArea));
+ // Set default log parameters for this scope.
+ SENF_LOG_DEFAULT_STREAM(foo::UserLog);
+ SENF_LOG_DEFAULT_LEVEL(senf::log::NOTICE);
- // Define an alias for emergency messages to the sysadmin.
- // The log area is inherited from the default at the place, where this
- // alias is used *not* where it is defined
- SENF_LOG_DEF_ALIAS(LogEmerg, (userLog)(senf::log::CRITICAL));
+ // Define an alias for emergency debug messages
+ // The log area is inherited from the default at the place, where this
+ // alias is used *not* where it is defined
+ SENF_LOG_DEFINE_ALIAS(LogEmerg, (senf::log::Debug)(senf::log::CRITICAL));
- void test();
+ void test();
- public:
- void froblize();
- };
+ public:
+ void froblize();
+ };
+ }
- void Froblizer::froblize()
+ void foo::Froblizer::froblize()
{
- SENF_LOG(("This is the Debug stream at level NOTICE in the FroblizeArea"));
- SENF_LOG((senf::log::WARNING) ("Same stream and area but at warning level"));
- SENF_LOG((LogEmerg) ("This goes to the userLog at level CRITICAL in the FroblizerArea"));
+ SENF_LOG(("This is the UserLog at level NOTICE in the FroblizeArea"));
+ SENF_LOG((senf::log::IMPORTANT) ("Same stream and area but at important level"));
+ SENF_LOG((LogEmerg) ("This goes to the DebugLog at level CRITICAL in the FroblizerArea"));
}
- void Froblizer::test()
+ void foo::Froblizer::test()
{
// Change the default log level for this method. stream and area are taken
// from the next scope up
- SENF_LOG_DEFAULTS((senf::log::VERBOSE));
+ SENF_LOG_DEFAULT_LEVEL(senf::log::VERBOSE);
+
+ SENF_LOG(("Log to UserLog stream in Froblizer area however at VERBOSE level"));
+ }
- SENF_LOG(("Log to Debug stream in Froblizer area however at VERBOSE level"));
+ int main(int, char **)
+ {
+ // Set up the routing targets
+ senf::log::ConsoleTarget & console (senf::log::ConsoleTarget::instance());
+ senf::log::FileTarget logfile ("my.log");
+
+ // Debug messages go to the console
+ console.route<senf::log::Debug>();
+ // Important user message are written to the log file
+ logfile.route<foo::UserLog, senf::log::IMPORTANT>();
}
\endcode
- Currently, the library is not implemented in any way. The interface has been defined up to a
- point and we have dummy implementations of the 'in-code' part of the interface. This is the
- part, which is called throughout the code. The configuration API is defined but we don't even
- have a template implementation. However, this allows starting to use the SENF Logger in newly
- developed code. Even though this code will unconditionally log everything to \c std::cerr for
- now and errors in the parameter specification will not be caught (since they are just ignored)
- the logging should work automatically as advertised as soon as the logger is completely
- implemented.
-
- I did not find any implementation which was not either completely convoluted, unusable or
- slow. So I turned to a macro based implementation which can provide all the design goals stated
- above.
-
- \section logger_compile_conf Compile time configuration
-
- The logger infrastructure allows to enable or disable log levels or areas at compile
- time. Levels or areas disabled at compile time do not generate any code. The compile time
- configuration is done in two parts: When defining log streams, default log levels and log level
- limits are defined. Additionally the \c SENF_LOG_CONF symbol can be defined to customize this
- default configuration.
-
- The \c SENF_LOG_CONF symbol is a Boost.Preprocessor style sequence of sequences:
- <pre>
- g++ ... -DSENF_LOG_CONF="((senf::log::Debug)(_)(DISABLED)) \
- ((senf::log::Debug)(foo::FooArea)(VERBOSE))" ...
- </pre>
- Each element defines the compile time limit for a stream and optional area.
-
\implementation I would have much preferred a more C++ like implementation. However given the
- design goals
- \li Flexible configuration at compile and runtime
- \li Concise usage and simple interface
- \li Zero overhead for compile-time disabled log messages
+ design goals
+ \li Flexible configuration at compile and runtime
+ \li Concise usage and simple interface
+ \li Zero overhead for compile-time disabled log messages
+
+ I did not find any non-mcaro implementation which was not either completely convoluted,
+ unusable or slow. So I turned to a macro based implementation which can provide all the
+ design goals stated above.
*/
\f