Efficient multi-threaded logging with configurable output channels. More...

Classes

class  LogChannel
 Logging channel. More...
class  Logger
 Writes log records to a target. More...
class  LogMessage
 Logs records with a logger. More...
class  LogRecord
 Log records can be added to a log. More...
class  LogTarget
 Target of log-messages. More...

Enumerations

enum  LogLevel {
}
 Severity of the log-message. More...

Detailed Description

The logging framework offers an efficient, extensible system to log messages from programs with multiple threads to a number of channels. Logging can be completely disabled at compile time, when the logging macros are used. At runtime, log messages are filtered by a level of severity. Filtering is very efficient, because log messages are not even built if their log level is too low. Currently three types of output channels exist, logging to files with file rolling, to the console and to the serial port. The logging framework can be extended by new channels.

Logging is an important feature of many applications. It can be used for debugging during the development process and to trace how a program executes once it is deployed. Crucial features of a logging framework are:

  • Performance
    High peformance can only be achieved if formatting of log records is avoided for disabled log statements. The costs boil down to an atomic integer comparison, and a branch. Further, logging can be disabled at compile time with via the preprocessor, in which case no instruction at all will be generated.

  • Thread-safety
    It is obvious that any modern library needs to be thread-safe. However, great care needs to be taken that synchronization overhead does not affect performance.

  • Easy Formatting
    In order to minimize the impact of a logging framework on the size of the source code, logging statements should be easy to write. This library allows to format log records with stream output operator just like for std::ostream.

  • Configuration
    The logging system should be configurable by both, API calls and configuration files. It must provide fine grained control in which parts of the application logging is enabled. It must be possible route the log records to different logs, for example the console or log files. The format of the records in the log should be configurable, and only contain the required information, which leads to smaller logs and a higher performance.

  • Usable during static initialization and deinitialization
    For example, logging statements may be executed indirectly when global objects are constructed or destructed. This should result in a static initialization fiasco.

  • Portability
    This library is extremly portable and has minimal dependencies. It requires only standard C++ and a standard C++ library.

The heart of the logging framwork is a hierarchy of log targets, which have a unique string ID. Applications format log records and use logger objects to write them to a target. Each target is configured with a threshold log level. Only records that are equally or more severe than the threshold are logged. In this case, the log records are written to the targets channel. Targets can log to the same channel, in fact, often all targets log to the same channel. The log channels perform output of log records i.e. to the console, if a console channel is selected or to a file if a file channel is selected, respectively. The threshold log level and channel of each log target in the hierarchy can be configured at runtime. Here is a typical example:

                       <root> id: ""
                         |    channel: console://
                         |    level: info
                         |
                         |
                       <app> id: "app"
                         |   channel: INHERIT
                         |   level: INHERIT
                         |
                         |
    .--------------------+-------------------.                
    |                                        |      
    |                                        |
<module1> id: "app.module1"              <module2> id: "app.module2"
          channel: file:///log.txt                 channel: INHERIT
          level: trace                             level: INHERIT

In this setup, three log targets are created. The root target is always persent and has the special empty string ID. The root target has one direct child, the target named "app". In this case, no log channel and level have been explicitly set for the target, so it inherits the attributes from its parent. The target "app" has two children, named "app.module1" and "app.module2". The string IDs indicate the position (path) of the target in the hierarchy. The target "app.module2" inherits all attributes from it parent, while the target "app.module1" overrides the log channel and level. With this mechanism based on inheritance, the parts of interest of the hierarchy can be enabled, while other parts of the hierarchy are suppressed.

Applications can use the API to set the threshold log levels and the channels of the targets. Possible log levels are:

Channels are configured by a channel URL. Possible channel URLs are:

The first opens a file channel writing to the file mylog.log. If the file size of 1000000 bytes is reached it will be renamed, and logging continues to a newly created mylog.log file. The parameter 'files' limits file rolling to a total number of five files. The second URL opens a channel to log to the console.

The format of the logging records can be configured with a format pattern string. The format pattern can contain text and specifiers, which are placeholders for the various elements of the log records. Specifiers are escaped with a percent sign in the format pattern string. For example, the pattern "%t %m" would write the time and the message for each log record separated by a space.

Here is a list of possible specifiers:

  • %c logging category
  • %d current date
  • %l log level (severity)
  • %m message text
  • %t current time
  • %F file where the record was logged
  • %L line number where the record was logged
  • %M method/function where the record was logged

TODO:

  • %T thread id
  • %P process id

The following code example above changes the log level and channel of the target named "app" to write records with a threshold level of Pt::System::Info to a log file:

Pt::System::Logger::setChannel("app", "file:///myfile.log");
static void setChannel(const std::string &target, const std::string &url)
Sets the channel to be used by the target and its children.
Definition Logger.h:326
static void setLogLevel(const std::string &target, LogLevel level)
Sets the log-level of the target and its children.
Definition Logger.h:316
static void setPattern(const std::string &pattern)
Set the pattern for log records.
@ Info
Infos and more severe messages.
Definition LogLevel.h:46

A log record pattern is applied to print the target ID, the time and the message text of the records to the logs.

Enumeration Type Documentation

◆ LogLevel

enum LogLevel
Enumerator
Fatal 

Only fatal messages.

Error 

Errors and more severe messages.

Warn 

Warnings and more severe messagess.

Info 

Infos and more severe messages.

Debug 

Debug logs and more severe messagess.

Trace 

Traces and more severe messages.