Introduction
This article is useful for those who want to see good design implementations. This article uses design patterns to solve the problem of logging in an effective way. Logging is an essential part of our development effort. Often, we don't know the kind of inputs that can be passed as parameters to the API/Calls written. This can produce unexpected behavior by the application. So to check/verify, we must log the details in various ways, like we can store it in XML, Text file, Email, Print on console, etc. Here, I have only provided text based implementation as it is easy to do. You can derive your classes to implement other loggers.
Background
If you really want to learn what is behind the scenes, then pick any simple book where design patterns have been given with examples. You will really learn something with this example as well.
Using the Code
A little description of the code is given below. Don't forget to copy the example configuration file in a given directory in the source code of demo application.
We have one main class which is the parent of all loggers, CLogger
.
class CLogger
{
public:
virtual void MakeLog( enum EnumLogType enumType ,string sData ) = 0;
virtual void AddDate() = 0;
virtual ~CLogger(){ }
protected:
friend class CLoggerManager;
virtual BOOL UpLoadSettings( ifstream &in_confile ){ return 0; }
};
Two main functions MakeLog
, AddDate
are provided which can serve to be either basic or the minimum functions for any logger. Now, any class derived from it must implement these two. The third function UpLoadSettings
is explained later. See the section below:
class CLoggerManager : public CLogger
{
string m_sConfigFile;
CLogResolver* m_pResolver;
void set_members( string &sConfigFile ,CLogResolver* pResolver );
CLoggerManager(){}
CLoggerManager( const CLoggerManager& );
CLoggerManager& operator = ( const CLoggerManager& );
vector<CLogger*> m_vOutput;
public:
static CLoggerManager& instantiate( string sConfigFile ,
CLogResolver* pResolver );
~CLoggerManager();
private:
BOOL LoadConfig();
public:
void MakeLog( enum EnumLogType enumType ,string sData );
};
CLoggerManager
class is an important part of logging. It acquires the interface from CLogger
but also acts as manager by letting various loggers initialize with the data required by each one of them.
First, understand the format of the configuration File. Config file contains the following:
- Class name
- Specific data
- again class name and specific data....
Resolver
returns the address of the new object whose class is specified in the class name. Then, UpLoadSettings
loads the specific data. Here, Resolver
is added as we need not complicate reading of the configuration file. The most important thing to remember about resolver
is that you can have derived classes of Resolver
to handle more Logger
s. Here, in the code, LoadConfig
function loads the loggers one by one in the specified vector.
BOOL LoadConfig()
{
try
{
if ( !m_pResolver )
return FALSE;
ifstream in_confile;
in_confile.open( m_sConfigFile.c_str() );
if ( !in_confile.is_open() )
return FALSE;
while ( 1 )
{
string sClassName;
in_confile >> sClassName;
if ( !sClassName.length() )
break;
CLogger* pLogger = m_pResolver->Resolve( sClassName );
if ( pLogger )
{
if ( !pLogger->UpLoadSettings( in_confile ) )
break;
}
else
break;
m_vOutput.push_back( pLogger );
}
}
catch(...)
{
}
return TRUE;
}
Now, if we make a call to CLoggerManager
to log, then it is routed to all the loggers inside, like this:
void MakeLog( enum EnumLogType enumType ,string sData )
{
for (vector<CLogger *>::const_iterator iter_output = m_vOutput.begin();
iter_output != m_vOutput.end() ;
++iter_output )
{
CLogger* p_output = *iter_output;
if ( p_output )
{
p_output->MakeLog( enumType ,sData );
}
}
}
Below is the code to make a single instance of Logger as we don't want to replicate our CLoggerManager
object (we don't need it).
static CLoggerManager& instantiate(string sConfigFile ,CLogResolver* pResolver)
{
static CLoggerManager m_Manager;
m_Manager.set_members( sConfigFile ,pResolver );
m_Manager.LoadConfig();
return m_Manager;
}
Have a look at the CFileLogger
code in source code files to see how it works. It's very simple to understand.
History
This is the first article I have posted. I have many more new ideas that can enhance knowledge. I am also a learner. I'll wait for your responses. If you have any suggestions, you are welcome.
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.