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
Figure 1. UML Design Class Inheritance Diagram
As you saw from Figure 1, the module classes are divided into two parts:
- Storage classes
- Logging classes
Storage Classes
The declaration of IStoreLog
:
class IStoreLog
{
public:
virtual ~IStoreLog( void ){};
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
- 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.
- 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.