Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

Logging::Logger Documentation

1

Legal stuff

Written by Markus Brueckner <dev@slash-me.net>

This code is public domain. Do whatever you want with it. I'm certainly not the one to blame for any damage this code may do. Though I've tried hard not to screw this up, you should probably not use this code in mission critical environments unless you really know what you're doing.

Objectives

That said let's start the technical things. This header file is intended for use as a lightweight, yet flexible logging and tracing frontend. The objectives to be reached were:

portability
The core code of the logger shall not be in need to be modified when using it on a new platform. It uses standard C++-features to achieve the goals set.
simple, std::ostream-like interface
Since C++-programmers are used to using the std::ostream-interface, the logger should maintain a similar one.
automatic removal of trace and debug code in release versions
While it is beneficial to excessivly use debug and trace messages in the development phase, it is mostly neither acceptable nor reasonable to bother the user of the final release code with such output. In most cases, he is neither interessted in reading those messages nor qualified to interpret them. Additionally the excessive use of such code unnecessarily increases code size and execution time. Therefore the logger must enable the developer to prevent unclusion of such code in the release version via a simple switch.
least possible use of the preprocessor
Normally, on would fulfill the previous objective by simply by simply implementing two sets of output macros, one for the debug version and one for the release version. This approach relies on the preprocessor heavily modifying the source code of a program. This way, the compiler "sees" another version of the code, than the programmer does, which may lead to strange effects. Therefore the logger shall not use the preprocessor except for the implementation of a single switch (i.e. no removal of code by the preprocessor). The actual removal of the debug code shall be done by the compiler.
thread safety on demand
With more and more software using a multithreaded programming model, the logger must be threadsafe to allow for it's use in such environments. As threading is inherentely bound to a specific platform, the logger shall allow to simply adapt it to a specific thread framework without the need to change it's code. This is done by making the mutex type a template parameter of the logger class. Additionally, the user should not be bothered to implement locking and unlocking of the logger. This is done by the logger itself in the background.

Usage

The typical usage of the logger looks like this (error checking left aside):

Logging::Logger *logger = new Logging::Logger(std::cout, Logging::LEVEL_TRACE);

logger << Logging::LEVEL_DEBUG << "This is a debug message." << Logging::endl;
logger << Logging::LEVEL_INFO  << "This is a info message." << Logging::endl;

delete logger;

This initializes the logger to output messages with at least trace level to std::cout. In case of the debug version of the code, both messages will therefore be print. The release version will remove the first message. The logger is able to print each and every datatype the user defined a std::ostream-output-operator for. Logging::Logger actually is just a typedef for Logging::TLogStream<EmptyMutex> which implements a logger with no thread safety at all. To implement actual thread safety, you'd have to write a class offering the two methods void Lock() and Unlock() and use it as a template parameter for TLogStream. An object of this class will be instantiated when the logger is created and destroyed when the logger is deleted. The logger will call Lock() each time, a message starts and Unlock() when the message ends. The two methods must block until the underlying synchronisation object is aquired or released.

The inclusion of debug and trace messages in the resulting binary is governed by the standard preprocessor macro NDEBUG. Whenever this is defined, we're compiling a release version and need to remove the according messages. If this macro is undefined, we're compiling debug code. The actual removal of the code is done by an optimizing compiler step, eliminating empty method stubs. To make this work, you should compile release code with some optimization level set. In case of the gcc the parameter -O is sufficient.


Generated on Fri Dec 16 21:45:56 2005 for Logging::Logger by  doxygen 1.4.4