Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Advanced Logging For All Kind of Applications

0.00/5 (No votes)
23 Feb 2002 1  
Simple to use classes for logging and tracing

Sample Image - gui_window.gif

Logging Module

This logging module has seven classes: CLog, CFuncLog, IStoreLog, CWinLog, CFileLog, CAutoCritic, CLogSimpleLock.

The main class of the Logging module is the CLog class and in most cases it must be a singleton in the application. Being a Singleton is not a requirement for it though.

The second most useful class is CFuncLog. This class is used to log functions when entering and leaving. Also, this class gives the developer an easy way to log any data. The Class has overloaded operators <<, that is why adding something to log is very easy.

UML Design of Logging Module

UML Diagram of Classes  
Figure 1. UML Design Class Inheritance Diagram

As you saw from Figure 1, the module classes are divided into two parts:

  1. Storage classes
  2. Logging classes

Storage Classes

The declaration of IStoreLog:

//////////////////////////////////////////////////////////////////////////
// Abstract class set three default function which must support any child.
// Any child must support buffered and non-buffered store

class IStoreLog
{
  public:
    virtual ~IStoreLog( void ){}; // virtual destructor
    virtual int FlushData() = 0;
    virtual int WriteString( const std::string &Message ) = 0;
    virtual int SetBufferLimit( long lSize ) = 0;
};  

Storage classes have the functionality to buffer with data flushing. By default, the storage class must store the data in its own buffer and only on a FlushData function call will it flush the buffer data to disk or elsewhere. As you understand the buffer of storage class in most cases is limited by system resources, that is why when the buffer reaches its limit, it will flush the data automatically. To set the buffer limit, use the function SetBufferLimit. By default, the Storage class implementation must allocate a buffer and only on a SetBufferLimit function call will it change its size.

To store string into storage, use the function WriteString. The Storage class must have no formatting and store RAW data as is.

Logging Classes

In this section, we have two classes: CLog - our main class and CFuncLog - helper class. Class CLog is declared in clog.h and its implementation is in clog.cpp file. Class CFuncLog is declared in cfuncLog.h, cfunclog.cpp.

Logger classes have special functions which make logging easier. While logging, you can configure trace output: If you have no need for time, then simply set the flag of CLog class using the function SetLogTime to false and the time will be not be added to the output. Also, you can change the output format of time by calling SetTimeFormat. By default, the class uses Long time format. In the header can be found two defines of most useful time formats. First is a long default to class format, second is a short one format without millisecond in output.

#define DEF_TIME_LONG_STR "%02u:%02u:%02u ms:%03u"
#define DEF_TIME_SHORT_STR "%02u:%02u:%02u"

WARNING: Time formatting string must always have 4 or less printf formatting templates, otherwise you will have a stack error.

Also for CLog class can be set such properties as:

  • Message Output Format - SetMessageFormat and GetMessageFormat functions
  • AutoFlush - SetAutoFlush and GetAutoFlush functions. true mean flushing of storage buffer after each trace message. Very useful when application is in alpha testing and has some GPFs in code. Second mode is useful when logging is needed for controlling state of application and it's not very critical by time - this is top performance mode of logging system.

For logging in CLog class, there are three functions:

  • LogRawString - trace raw string without formatting to storage class
  • LogString - trace message with special level and formatting. There are two functions with the same name, only difference is a format of output string, in first case is a std::string on second simple char *.
  • LogFormatString - formatting function - wrapper on printf function

In many cases. the developer will need more than three categories of messages, that is why in CLog class is virtual function LevelText. As input parameter, it will have number of required LEVEL. Function will return string with Category Name. By default, on Category name class set limitation on 12 symbols, but this can be changed by SetMessageFormat function template string.

To use Logging in application, include into project such headers:

#include "clog.h"
#include "cfunclog.h"
#include "cwinlog.h"  // include it if you want logging into GUI window
#include "cfilelog.h" // include it if you want logging into files
...

CFuncLog class is not required - it's only to simplify logging of most used features, like: entering and leaving of function. Special formatting and everything needed to logging operations are implemented in CLog file. That is why you can choose: use it or not.

NOTE: CWinLog class stores traced messages in window and are not multiprocess safe. Otherwise, for multiprocess logging only CFileLog class can be used. By using CFileLog, all traced messages are stored in file. All file operations are synchronized by OS.

How to Use the Module

  1. Create instance of CLog class:
    CLog *m_pLog = new CLog( new CFileLog( "c:\\log.log" ), LOG_MAX_LEVEL, true ); 

    First parameter of the CLog constructor must be pointer of class which supports IStoreLog interface. In module are two implementations of IStoreLog virtual class: CWinLog and CFileLog.

    As you understand, CWinLog class creates GDI window in which you can display traced messages and second log class stores logging into file.

    As a output file can be used any OS device or named pipe or something else, which uses syntax of CreateFile API function.

    Second parameter is an upper limit of messages. It must be set to needed upper value limit.

    So if you set it to 0, then in log output will be only ERROR messages. If you set it to 1, then in log will be ERROR and WARNING messages... and so on.

    Third param said to CLog class instance is it a parent of IStoreLog class instance or not. By default, this value is true. So CLog Class on destroy delete instance of IStoreLog class implementation.

  2. If you want to log functions entering and leaving, then do like this:
    CRepTestApp::CRepTestApp()
    {
      CFuncLog log( m_pLog, "CRepTestApp::CRepTestApp" );
      ...
    }

    Such code will add into log entering and leaving of function code. Here, I have used feature of automatic variables. On Construct into log will be added "enter ..." message and on destroy into log will be added "leave ..." message. To add something to log, you can type such code:

    int something = 100;
    log << something;
    ...

    such code will add 100 into log output.

    WARNING: operator << stores log values in RAW format.

    To add message to log correctly, use LogString function of the CFuncLog class.

If you want to store log into any other place, then you must write implementation of IStoreLog class and use its instance as a constructor param. CAutoCritic and CLogSimpleLock classes is a wrapper on Critical Section API of windows. Such classes are implemented in stand alone file with namespace LOGGER and can be freely used by other IStoreLog class implementations.

History

First logger module was implemented in 2000 and after that was rewritten sometimes. I found that in many cases, the Logger system was a requirement for commercial projects, that is why I spent some time and wrote such an easy to use and extendible logger/trace subsystem.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here