XLL+ Class Library (6.3)

Logging

XLL+ (from version 6.2 onwards) contains a logging framework, cpplog, which helps you to write diagnostic and other information to log files.

log4cxx

The API for this framework is based on that of the Apache Foundation's log4cxx. log4cxx is more efficient, more powerful and more complete than cpplog. However, it is a lengthy package to install, needs extra steps to build, and comes with a lot of extra baggage.

The cpplog framework is designed so that it is trivial to switch from it to log4cxx, if you wish. If at any time you find that the cpplog framework is not providing the functionality or performance that you need, you should consider switching to log4cxx.

Overview

There are 3 aspects to logging using this framework, which are described in more detail in the next topics:

Example

Below is a class that writes to the logging framework.

CopyC++
class MyClass
{
private:
    static LoggerPtr m_logger;
public:
    void DoSomething(int value, const TCHAR* str)
    {
        LOG_INFO(m_logger, _T("About to do something with ") << value << _T(" and ") << str);
        LOG_TRACE(m_logger, _T("Leaving DoSomething"));
    }
};

LoggerPtr MyClass::m_logger = Logger::getLogger(_T("MyClass"));

Note the LOG_xxx macros in the DoSomething method. The first macro means:

  1. Look at the logger pointed to by m_logger.
  2. If the logger is set to report log events of INFO level or above, continue. Otherwise, stop now.
  3. Evaluate the expression on the right - "About to do something with [value] and [str]" - and stream it to all attached log sinks.

Below is the context within which the above logging code is used:

CopyC++
int _tmain(int argc, _TCHAR* argv[])
{
    // Configure the logging framework
    BasicConfigurator::configure(_T("%-5p %c - %m%n"), LL_DEBUG);

    // Get a logger pointer and use it
    LoggerPtr logger = Logger::getLogger(_T("main"));
    LOG_DEBUG(logger, _T("Starting main"));

    // Create an instance of MyClass, and use it.
    MyClass c;
    c.DoSomething(15, _T("a string value"));

    // Write to the "main" logger
    LOG_DEBUG(logger, _T("Leaving main"));
}

The first part configures the root logger to write events of severity level DEBUG and above to the console, using a simple formatting pattern. In effect this means that all events except TRACE events will be reported.

The second part gets a logger pointer for the logger "main", which it then uses to write a debug event.

After creating and using an instance of MyClass - which also does some logging - the last part of _tmain writes another debug message to the log.

The output to the console will be as follows:

DEBUG main - Starting main
INFO  MyClass - About to do something with 15 and a string value
DEBUG main - Leaving main

Notice that the TRACE event from DoSomething() is suppressed, because it is of a lower severity than any of the loggers that it is sent to. All other events are reported to the console.

Next: Directing log events >>