C++ : classe Logger

De Wiki de Calcul Québec
Aller à : Navigation, rechercher
Autres langues :anglais 100% • ‎français 100%

C++ : une classe Logger pour écrire des messages

La plupart des programmes écrivent des messages d'information et d'erreur dans un journal (en anglais, log). Par exemple, le journal peut servir à documenter le déroulement d'une simulation. Souvent, il est un instrument précieux dans la détection et le diagnostic des anomalies.

La classe Logger présentée ici permet à une application de tenir un journal d'exécution. Celui-ci peut être écrit dans un fichier, ou dirigé vers la sortie standard. Les messages envoyés au Logger ont une priorité de type Logger::Priority. Les cinq priorités décrivent la gravité des messages. Typiquement, on donnera la priorité ERROR pour signaler une erreur sévère et DEBUG pour afficher une simple trace de débogage. Le niveau de journalisation est fixé par le paramètre minPriority de la méthode Logger::Start. Un message de priorité inférieure à minPriority n'est pas inscrit dans le journal.

Logger est une classe singleton. Cela signifie qu'il ne peut en exister qu'une seule instance. Ici, cette instance est un membre privé et statique de la classe elle-même. Le code appelant ne la manipule jamais directement. Il le fait à travers les méthodes statiques Start, Stop et Write. Notez qu'il existe des manières plus sophistiquées de réaliser le motif du singleton (voir par exemple www.codeproject.com/cpp/singleton.asp). Cependant, notre implémentation très simple sert bien les besoins modestes du Logger.


Fichier : 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;
    }
}


Les macros suivantes permettent la compilation conditionnelle du code de journalisation. Ainsi, pour accélérer un traitement, on peut omettre la directive ENABLE_LOGGER (ou l'invalider localement avec #undef).


Fichier : 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


Exemple d'utilisation :

Fichier : exemple_logger.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