Sunday, December 24, 2006

The Simplest Logging Class in C++



I want to create the simplest ever logging class in C++, so I created a single Log.h file and created a sample application that uses it.
This was very useful in the small application I am working on.



It compile with gcc and it works as expected.

known problems:
the Log.write() function may make problems in multithreaded applications, in such case you must put a critical section around it.

//////////////////////////////////////////////////////////////////////////////////////////////
//main.cpp
//logging header file
#include <stdio.h>
#include "log.h"

LOG_DECLARE;

int main()
{
//initialize file logger
LOG_INIT("main.log");

LOG_MSG("Application initialization");

printf("This is the application\n");

LOG_MSG("Application end");

}
//////////////////////////////////////////////////////////////////////////////////////////////

Look at the Log.h file

//////////////////////////////////////////////////////////////////////////////////////////////
//log.h

#ifndef __LOG_H
#define __LOG_H
//It is bad to include files within other include files, but this is an exception to simplify the code
#include <stdio.h>

//must be put in global scope and used once in all files
#define LOG_DECLARE Log __log;
//used in any file need to access the log files, except the file that has LOG_DECLARE statment
#define LOG_USE(); extern Log __log;
//init log files, called once in program initialization
#define LOG_INIT(fileName) do{if(fileName!= NULL)__log.init(fileName); else printf("error init log file %s", fileName);}while(0);

//here are the different levels of logging
#define LOG_VERBOSE(msg) __log.write("verbose", msg, __FILE__, __LINE__); //detaild info
#define LOG_MSG(msg) __log.write("msg", msg, __FILE__, __LINE__); //brief info
#define LOG_WARN(msg) __log.write("warn", msg, __FILE__, __LINE__); //warning
#define LOG_ERR(msg) __log.write("error", msg, __FILE__, __LINE__); //error
#define LOG_FATAL(msg) __log.write("fatal", msg, __FILE__, __LINE__); //fatal error

class Log
{
FILE *fp;
bool logOk;

public:

Log()
{fp = NULL;}
~Log() //the destructor closes the file
{close();}

void init(char *pfileName)
{ if(pfileName != NULL) {fp = fopen(pfileName, "a+"); if(fp != NULL) fseek(fp, 0, SEEK_END);} }

void close()
{if(fp != NULL) fclose(fp); fp = NULL;}

//FIXME: A critical section is required to protect the file writing function in multithreading programms
void write(char *pType, char *pMsg, char *pFileName, int lineNo)
{ if(fp != NULL) fprintf(fp, "%s\t%s\t%s\t%s\t%d\t%s\n", pType, __DATE__, __TIME__, pFileName, lineNo, pMsg); }
};

#endif

3 comments:

Anonymous said...

Ii is simple and very useful logger

Anonymous said...

Excellent Job! Very nice logger.

Anonymous said...

I found 2 errors:
1) under Linux it doesn't work because __log is already defined. You should use another name, for example __sLog
2) you should flush the buffer every time you write to the file to have a "real time" logging. Add fflush(fp) after the fprintf.

I would modify the #define LOG_VERBOSE to write only if I define the VERBOSE preprocessor variable. How can I do it?