C++: Logger class

De Wiki de Calcul Québec
Aller à : Navigation, rechercher
Cette page est une traduction de la page C++ : classe Logger et la traduction est complétée à 100 % et à jour.

Autres langues :anglais 100% • ‎français 100%

C++: a Logger class to write messages

Most programs write informational and error messages to a journal or log. For example, a log can document how a simulation runs. Often it is a precious instrument allowing to detect and diagnose anomalies.

The Logger class presented here allows to keep a running log. It can be written to a file, or be redirected to standard output. Messages sent to Logger have a priority of type Logger::Priority. There are five priorities to describe the severity of the messages. Typically, one gives the ERROR priority to show a severe error and DEBUG to display a simple debugging trace. The logging level is set by the parameter minPriority of the Logger::Start method. A message with lower priority than minPriority is not written to the log.

Logger is a singleton class. That means the only one instance can exist at any one time. Here, this is instance is a private static member of the class itself. The calling code never manipulates the instance directly. It is done instead using the static methods Start, Stop, and Write. Note that there exist more sophisticated methods to implement a singleton (see for example www.codeproject.com/cpp/singleton.asp). Nevertheless, our very simple implementation serves the modest needs of the Logger very well.


File : logger.cpp
#include <string>
#include <fstream>
#include <iostream>
 
using namespace std;
 
class Logger
{
public:
    // log priorities
    enum Priority
    {
        DEBUG,
        CONFIG,
        INFO,
        WARNING,
        ERROR
    };
 
    // start/stop logging
    // - messages with priority >= minPriority will be written in log
    // - set logFile = "" to write to standard output
    static void Start(Priority minPriority, const string& logFile);
    static void Stop();
 
    // write message
    static void Write(Priority priority, const string& message);
 
private:
    // Logger adheres to the singleton design pattern, hence the private
    // constructor, copy constructor and assignment operator.
    Logger();
    Logger(const Logger& logger) {}
    Logger& operator = (const Logger& logger) {}
 
    // private instance data
    bool        active;
    ofstream    fileStream;
    Priority    minPriority;
 
    // names describing the items in enum Priority
    static const string PRIORITY_NAMES[];
    // the sole Logger instance (singleton)
    static Logger instance;
};
 
 
// --------------------------------------
// static members initialization
// --------------------------------------
 
const string Logger::PRIORITY_NAMES[] =
{
    "DEBUG",
    "CONFIG",
    "INFO",
    "WARNING",
    "ERROR"
};
 
Logger Logger::instance;
 
 
// --------------------------------------
// function implementations
// --------------------------------------
 
Logger::Logger() : active(false) {}
 
void Logger::Start(Priority minPriority, const string& logFile)
{
    instance.active = true;
    instance.minPriority = minPriority;
    if (logFile != "")
    {
        instance.fileStream.open(logFile.c_str());
    }
}
 
void Logger::Stop()
{
    instance.active = false;
    if (instance.fileStream.is_open())
    {
        instance.fileStream.close();
    }
}
 
void Logger::Write(Priority priority, const string& message)
{
    if (instance.active && priority >= instance.minPriority)
    {
        // identify current output stream
        ostream& stream
            = instance.fileStream.is_open() ? instance.fileStream : std::cout;
 
        stream  << PRIORITY_NAMES[priority]
                << ": "
                << message
                << endl;
    }
}


The following macros allow to conditionally compile the logging code. So, to speed up a simulation, one can remove the ENABLE_LOGGER directive (or invalidate it locally using #undef).


File : logger.h
#ifdef ENABLE_LOGGER
 
#define LOGGER_START(MIN_PRIORITY, FILE) Logger::Start(MIN_PRIORITY, FILE);
#define LOGGER_STOP() Logger::Stop();
#define LOGGER_WRITE(PRIORITY, MESSAGE) Logger::Write(PRIORITY, MESSAGE);
 
#else
 
#define LOGGER_START(MIN_PRIORITY, FILE)
#define LOGGER_STOP()
#define LOGGER_WRITE(PRIORITY, MESSAGE)
 
#endif


Example how to use it:

File : logger_example.cpp
...
LOGGER_START(Logger::INFO, "")
LOGGER_WRITE(Logger::CONFIG, "input file is " + inputFileName)
...
try
{
    LOGGER_WRITE(Logger::DEBUG, "trying to allocate buffer")
 
    if (bufferSize <= 0)
    {
        throw(string("invalid buffer size"));
    }
 
    buffer = new char[bufferSize];
    if (buffer == NULL)
    {
        throw(string("allocation failure"));
    }
}
catch (const string& str)
{
    LOGGER_WRITE(Logger::ERROR, "exception caught: " + str)
    exit(EXIT_FAILURE);
}
...
if (nbParticles == 0)
{
    LOGGER_WRITE(Logger::WARNING, "no more particles")
}
...


Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Ressources de Calcul Québec
Outils
Partager