Click here to Skip to main content
15,880,796 members
Articles / Desktop Programming / MFC

Advanced Logging For All Kind of Applications

Rate me:
Please Sign up or sign in to vote.
4.72/5 (13 votes)
23 Feb 2002CPOL5 min read 167.4K   6.2K   116   36
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:

C++
//////////////////////////////////////////////////////////////////////////
// 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.

C++
#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:

C++
#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:
    C++
    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:
    C++
    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:

    C++
    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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO ArtfulBits Inc.
Ukraine Ukraine
Name:Kucherenko Oleksandr

Born:September 20, 1979

Platforms: Win32, Linux; - well known and MS-DOS; Win16; OS/2 - old time not touched;

Hardware: IBM PC

Programming Languages: Assembler (for Intel 80386); Borland C/C++; Borland Pascal; Object Pascal; Borland C++Builder; Delphi; Perl; Java; Visual C++; Visual J++; UML; XML/XSL; C#; VB.NET; T-SQL; PL/SQL; and etc.

Development Environments: MS Visual Studio 2001-2008; MS Visual C++; Borland Delphi; Borland C++Builder; C/C++ any; Rational Rose; GDPro; Together and etc.

Libraries: STL, ATL, WTL, MFC, NuMega Driver Works, VCL; .NET 1.0, 1.1, 2.0, 3.5; and etc.

Technologies: Client/Server; COM; DirectX; DirectX Media; BDE; HTML/DHTML; ActiveX; Java Servlets; DCOM; COM+; ADO; CORBA; .NET; Windows Forms; GDI/GDI+; and etc.

Application Skills: Databases - design and maintain, support, programming; GUI Design; System Programming, Security; Business Software Development. Win/Web Services development and etc.

Comments and Discussions

 
QuestionSmall bug:File writing does not First In First Write Pin
Member 112015586-May-15 17:41
Member 112015586-May-15 17:41 
QuestionLicense agreement? Pin
Francisco José Sen del Prado24-Jun-09 0:57
Francisco José Sen del Prado24-Jun-09 0:57 
AnswerRe: License agreement? Pin
Oleksandr Kucherenko24-Jun-09 2:49
Oleksandr Kucherenko24-Jun-09 2:49 
GeneralRe: License agreement? Pin
Francisco José Sen del Prado24-Jun-09 11:34
Francisco José Sen del Prado24-Jun-09 11:34 
Generalthe bug of cwinlog [modified] Pin
zhanshen5318-Mar-09 16:58
zhanshen5318-Mar-09 16:58 
GeneralRe: the bug of cwinlog [modified] Pin
mlh4627-Nov-12 22:12
mlh4627-Nov-12 22:12 
GeneralExcellent work! Pin
jcoco11-May-08 12:16
jcoco11-May-08 12:16 
GeneralRe: Excellent work! Pin
Oleksandr Kucherenko11-May-08 21:36
Oleksandr Kucherenko11-May-08 21:36 
Generalnot serious Pin
DmityShm2-Apr-07 21:44
DmityShm2-Apr-07 21:44 
GeneralRe: not serious Pin
Oleksandr Kucherenko2-Apr-07 21:53
Oleksandr Kucherenko2-Apr-07 21:53 
GeneralRe: not serious Pin
DmityShm2-Apr-07 22:49
DmityShm2-Apr-07 22:49 
GeneralRe: not serious Pin
Oleksandr Kucherenko2-Apr-07 22:54
Oleksandr Kucherenko2-Apr-07 22:54 
QuestionWhich tool used for UML Design ? Pin
ana_v12315-Sep-05 3:13
ana_v12315-Sep-05 3:13 
AnswerRe: Which tool used for UML Design ? Pin
Oleksandr Kucherenko2-Apr-07 21:55
Oleksandr Kucherenko2-Apr-07 21:55 
QuestionWhy don't this support unicode? Pin
Lam Ngo12-Jan-05 5:20
Lam Ngo12-Jan-05 5:20 
AnswerRe: Why don't this support unicode? Pin
Oleksandr Kucherenko2-Apr-07 22:00
Oleksandr Kucherenko2-Apr-07 22:00 
Generalchange operator&lt;&lt; (char *) Pin
Björn Carlsson1-Dec-04 2:49
Björn Carlsson1-Dec-04 2:49 
GeneralRe: change operator&lt;&lt; (char *) Pin
Oleksandr Kucherenko2-Apr-07 22:03
Oleksandr Kucherenko2-Apr-07 22:03 
GeneralSynchronization bug Pin
Bogdan Gonciulea30-Nov-04 1:31
Bogdan Gonciulea30-Nov-04 1:31 
GeneralRe: Synchronization bug Pin
Oleksandr Kucherenko30-Nov-04 2:09
Oleksandr Kucherenko30-Nov-04 2:09 
Generalon current moment code not supported yet Pin
Oleksandr Kucherenko19-Oct-04 1:40
Oleksandr Kucherenko19-Oct-04 1:40 
Questioncan not set log file size Pin
xqyz888819-Oct-04 0:33
xqyz888819-Oct-04 0:33 
GeneralConsole app Pin
rromerot28-Apr-04 8:45
rromerot28-Apr-04 8:45 
GeneralRe: Console app Pin
Oleksandr Kucherenko28-Apr-04 21:44
Oleksandr Kucherenko28-Apr-04 21:44 
Generalwhy don't call FlushFileBuffers in ~CFileLog Pin
zmxjh22-Oct-03 9:02
zmxjh22-Oct-03 9:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.