Implémentation d'une classe de journalisation simple en C++

Cet article présente une classe C++ minimaliste, nommée SimpleLogger, conçue pour répondre à ces exigences de base. Elle permet d'enregistrer des messages textuels vers la sortie standard (console) ou vers un fichier spécifié, et offre des fonctions pour gérer le flux de sortie.

Définition de la classe SimpleLogger

La classe SimpleLogger encapsule la logique de gestion des sorties. Elle utilise les flux C++ modernes (std::ofstream pour les fichiers et std::cout/std::cerr pour la console) pour une gestion cohérente et sécurisée des I/O.

Voici l'en-tête de la classe SimpleLogger.hpp :

#ifndef SIMPLE_LOGGER_HPP
#define SIMPLE_LOGGER_HPP

#include <string>
#include <fstream> // Pour std::ofstream
#include <iostream> // Pour std::cout, std::cerr

class SimpleLogger {
public:
    // Énumération pour définir la cible de sortie des journaux.
    enum class OutputTarget {
        Console,
        File
    };

    // Constructeur. Si le nom de fichier est vide, la journalisation se fait sur la console.
    // Sinon, le fichier est ouvert.
    explicit SimpleLogger(const std::string& filename = "");

    // Destructeur. Ferme le flux de fichier si celui-ci est ouvert.
    ~SimpleLogger();

    // Enregistre un message vers la cible active (console ou fichier).
    void log(const std::string& message);

    // Ajoute un caractère de nouvelle ligne à la sortie.
    void endLine();

    // Vide le contenu du fichier de journalisation si la cible est un fichier.
    void clearLogFile();

    // Définit la console comme cible de journalisation.
    void setConsoleOutput();

    // Définit le fichier comme cible de journalisation.
    // Tente d'ouvrir le fichier si ce n'est pas déjà fait ou s'il a été fermé.
    void setFileOutput();

    // Accesseurs
    OutputTarget getOutputTarget() const { return _currentOutputTarget; }
    std::string getLogFilePath() const { return _logFilePath; }

private:
    // Empêche la copie et l'affectation pour les objets SimpleLogger.
    SimpleLogger(const SimpleLogger&) = delete;
    SimpleLogger& operator=(const SimpleLogger&) = delete;

    std::ofstream _outFile;
    std::string _logFilePath;
    OutputTarget _currentOutputTarget;

    // Fonction d'aide pour ouvrir le fichier de journalisation.
    void _openFile(const std::string& filename);
};

#endif // SIMPLE_LOGGER_HPP

Implémentation de la classe SimpleLogger

Le fichier d'implémentation SimpleLogger.cpp contient la logique de chaque méthode, gérant l'ouverture, la fermeture et l'écriture des flux, ainsi que le basculement entre la console et le fichier.

#include "SimpleLogger.hpp"

// Constructeur: Initialise la cible à la console par défaut.
// Si un nom de fichier est fourni, la cible est définie sur le fichier et une tentative d'ouverture est effectuée.
SimpleLogger::SimpleLogger(const std::string& filename)
    : _currentOutputTarget(OutputTarget::Console) {
    if (!filename.empty()) {
        _logFilePath = filename;
        _currentOutputTarget = OutputTarget::File;
        _openFile(filename);
    }
}

// Destructeur: S'assure que le flux de fichier est fermé.
SimpleLogger::~SimpleLogger() {
    if (_outFile.is_open()) {
        _outFile.close();
    }
}

// Fonction d'aide pour ouvrir le fichier de journalisation.
// Ferme tout fichier existant avant d'en ouvrir un nouveau en mode 'append' (ajout).
void SimpleLogger::_openFile(const std::string& filename) {
    if (_outFile.is_open()) {
        _outFile.close();
    }
    _outFile.open(filename, std::ios::app); // Ouvre en mode ajout, crée le fichier s'il n'existe pas.
    if (!_outFile.is_open()) {
        std::cerr << "Erreur: Impossible d'ouvrir le fichier de journalisation: " << filename << std::endl;
        _currentOutputTarget = OutputTarget::Console; // Retourne à la console en cas d'erreur.
    }
}

// Enregistre un message: écrit sur la console ou dans le fichier, selon la cible actuelle.
void SimpleLogger::log(const std::string& message) {
    if (_currentOutputTarget == OutputTarget::Console) {
        std::cout << message;
    } else if (_currentOutputTarget == OutputTarget::File) {
        if (_outFile.is_open()) {
            _outFile << message;
        } else {
            std::cerr << "Erreur: Le fichier de journalisation n'est pas ouvert pour l'écriture. Affichage sur console." << std::endl;
            std::cout << message; // Affichage de secours sur la console.
        }
    }
}

// Ajoute une nouvelle ligne.
void SimpleLogger::endLine() {
    if (_currentOutputTarget == OutputTarget::Console) {
        std::cout << std::endl;
    } else if (_currentOutputTarget == OutputTarget::File) {
        if (_outFile.is_open()) {
            _outFile << std::endl;
        }
    }
}

// Vide le fichier de journalisation en le réouvrant en mode troncature.
void SimpleLogger::clearLogFile() {
    if (_currentOutputTarget == OutputTarget::File && !_logFilePath.empty()) {
        if (_outFile.is_open()) {
            _outFile.close();
        }
        _outFile.open(_logFilePath, std::ios::trunc); // Réouvre en mode troncature pour vider le contenu.
        if (!_outFile.is_open()) {
            std::cerr << "Erreur: Impossible de vider le fichier de journalisation: " << _logFilePath << std::endl;
        }
    }
}

// Définit la sortie sur la console.
void SimpleLogger::setConsoleOutput() {
    _currentOutputTarget = OutputTarget::Console;
}

// Définit la sortie sur le fichier. Si le fichier n'est pas déjà ouvert et qu'un chemin est défini, tente de l'ouvrir.
void SimpleLogger::setFileOutput() {
    _currentOutputTarget = OutputTarget::File;
    if (!_logFilePath.empty() && !_outFile.is_open()) {
        _openFile(_logFilePath);
    }
}

Exemple d'utilisation

Le code suivant démontre comment instancier la classe SimpleLogger, basculer entre la console et le fichier, et utiliser ses différentes méthodes.

#include "SimpleLogger.hpp"
#include <iostream>

void testSimpleLogger() {
    std::cout << "--- Test du journalisateur sur console ---" << std::endl;
    SimpleLogger consoleLogger; // Journalisation par défaut sur console
    consoleLogger.log("Bonjour, ceci est un message sur console.");
    consoleLogger.endLine();
    consoleLogger.log("Un autre message avec des nombres : 12345.");
    consoleLogger.endLine();

    std::cout << "\n--- Test du journalisateur sur fichier ---" << std::endl;
    // Spécifiez un chemin de fichier pour le test.
    // Assurez-vous que le répertoire existe ou modifiez le chemin.
    const std::string logFilePath = "simple_log_test.txt";
    SimpleLogger fileLogger(logFilePath);

    fileLogger.log("Premier message dans le fichier.");
    fileLogger.endLine();
    fileLogger.log("Ceci devrait être ajouté à la suite.");
    fileLogger.endLine();

    std::cout << "Changement de mode vers console temporairement..." << std::endl;
    fileLogger.setConsoleOutput();
    fileLogger.log("Ce message va sur la console pendant que le fichier est ouvert.");
    fileLogger.endLine();

    std::cout << "Retour au mode fichier..." << std::endl;
    fileLogger.setFileOutput();
    fileLogger.log("Et maintenant de retour au fichier.");
    fileLogger.endLine();

    std::cout << "Vidage du contenu du fichier de journalisation (" << logFilePath << ")..." << std::endl;
    fileLogger.log("Ceci sera supprimé car le vidage aura lieu après.");
    fileLogger.endLine();
    fileLogger.clearLogFile(); // Vide le fichier
    fileLogger.log("Ceci est le premier message après le vidage.");
    fileLogger.endLine();
    fileLogger.log("Le fichier doit contenir seulement ces deux lignes.");
    fileLogger.endLine();

    std::cout << "\n--- Fin des tests ---" << std::endl;
    std::cout << "Vérifiez le fichier '" << logFilePath << "' pour les résultats." << std::endl;
}

int main() {
    testSimpleLogger();
    return 0;
}

Ce SimpleLogger fournit une base solide pour des besoins de journalisation rudimentaires, tout en étant extensible pour des fonctionnalités plus avancées si nécessaire.

Étiquettes: C++ journalisation Gestion de fichiers Flux C++ std::ofstream

Publié le 23 juillet à 00h04