web-dev-qa-db-fra.com

Petite classe de bûcheron

Je cherche un petit système de journalisation léger en c ++. J'ai trouvé des frameworks existants, mais je n'ai pas besoin de toutes leurs fonctionnalités pour le moment. Je recherche principalement un petit système capable, par exemple, de configurer le fichier de sortie au niveau du journal. Je cherche une solution existante car je ne veux pas réinventer la roue.

26
herzl shemuelian

Je recommande fortement ce système de journalisation simple: http://www.drdobbs.com/cpp/201804215 . Il est composé d'un seul fichier d'en-tête. Je l'ai utilisé avec succès sous Linux, Windows et Mac OS X.

Vous écrivez dans le journal comme ceci:

FILE_LOG(logWARNING) << "Ops, variable x should be " << expectedX << "; is " << realX;

J'aime beaucoup la syntaxe du flux. Il est discret, typé et expressif. La structure de journalisation ajoute automatiquement un \n à la fin de la ligne, ainsi que la date, l'heure et l'indentation.

La configuration des journaux est assez simple:

FILELog::ReportingLevel() = logDEBUG3;
FILE* log_fd = fopen( "mylogfile.txt", "w" );
Output2FILE::Stream() = log_fd;

Ce cadre est également facile à étendre. Au travail, nous avons récemment apporté quelques adaptations pour qu'il utilise maintenant un std::ofstream au lieu d'un FILE*. En conséquence, nous sommes maintenant en mesure d'ajouter des fonctionnalités de Nice telles que le cryptage des journaux, en chaînant les flux.

37
Pedro d'Aquino

Pour ceux qui veulent une solution simple, je recommande: easylogging ++

En-tête unique uniquement bibliothèque de journalisation C++. Il est extrêmement léger. robuste, performant, fileté et sûr, composé de plusieurs fonctionnalités intégrées. Il offre la possibilité d'écrire des journaux dans votre propre format personnalisé. Il fournit également une assistance pour la journalisation de vos classes, bibliothèques tierces, conteneurs STL et tiers, etc.

Cette bibliothèque a tout intégré pour empêcher l'utilisation de external bibliothèques.

Exemple simple: (exemples plus avancés disponibles sur le lien ci-dessus).

#include "easylogging++.h"

INITIALIZE_EASYLOGGINGPP

int main(int argv, char* argc[]) {
   LOG(INFO) << "My first info log using default logger";
   return 0;
}

Exemple de sortie dans une classe:

2015-08-28 10: 38: 45,900 DEBUG [défaut] [utilisateur @ localhost] [Config :: Config (chaîne constante)] [src/Config.cpp: 7] Lecture du fichier de configuration: 'config.json'

J'ai essayé log4cpp et boost :: log mais ils ne sont pas aussi faciles que celui-ci.

EXTRA CONTENT: Version minimale - En-tête LOG

J'ai créé un petit code pour des applications encore plus simples basées sur easylogging mais ne nécessitant aucune initialisation (sachez qu'il n'est probablement pas thread-safe). Voici le code:

/* 
 * File:   Log.h
 * Author: Alberto Lepe <[email protected]>
 *
 * Created on December 1, 2015, 6:00 PM
 */

#ifndef LOG_H
#define LOG_H

#include <iostream>

using namespace std;

enum typelog {
    DEBUG,
    INFO,
    WARN,
    ERROR
};

struct structlog {
    bool headers = false;
    typelog level = WARN;
};

extern structlog LOGCFG;

class LOG {
public:
    LOG() {}
    LOG(typelog type) {
        msglevel = type;
        if(LOGCFG.headers) {
            operator << ("["+getLabel(type)+"]");
        }
    }
    ~LOG() {
        if(opened) {
            cout << endl;
        }
        opened = false;
    }
    template<class T>
    LOG &operator<<(const T &msg) {
        if(msglevel >= LOGCFG.level) {
            cout << msg;
            opened = true;
        }
        return *this;
    }
private:
    bool opened = false;
    typelog msglevel = DEBUG;
    inline string getLabel(typelog type) {
        string label;
        switch(type) {
            case DEBUG: label = "DEBUG"; break;
            case INFO:  label = "INFO "; break;
            case WARN:  label = "WARN "; break;
            case ERROR: label = "ERROR"; break;
        }
        return label;
    }
};

#endif  /* LOG_H */

Usage:

#include "Log.h"

int main(int argc, char** argv) {
    //Config: -----(optional)----
    structlog LOGCFG = {};
    LOGCFG.headers = false; 
    LOGCFG.level = DEBUG;
    //---------------------------
    LOG(INFO) << "Main executed with " << (argc - 1) << " arguments";
}

Ce code imprime le message en utilisant "cout", mais vous pouvez le changer pour utiliser "cerr" ou ajouter un fichier, etc. J'espère qu'il sera utile à quelqu'un. (Remarque: je ne suis en aucun cas un expert en C++, ce code peut donc exploser dans des cas extrêmes). 

16
lepe

Je recommande d'essayer plog library (je suis l'auteur). C'est environ 1000 lignes de code, en-tête seulement et facile à utiliser:

#include <plog/Log.h>

int main()
{
    plog::init(plog::debug, "Sample.log");

    LOGD << "Hello log!";
    LOGD_IF(true) << "conditional logging";
    return 0;
}
7
Sergey Podobry

jusqu'à présent, tous les enregistreurs mentionnés utilisent des macros pour enregistrer les appels. Pour moi, c'est si moche, je me fiche de l'amélioration de la performance que cela donne, je ne vais pas m'en approcher.

https://github.com/gabime/spdlog est ce que j'aime. Nettoyer la syntaxe, gère tous les usages typiques. Rapide et petit. par exemple. pour un enregistreur de fichiers c'est:

auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic.txt");
my_logger->info("Some log message");
7
AbsolutelyFreeWeb

Si vous n'avez pas de limite de taille sur le projet et que vous vous attendez à ce qu'il vive longtemps, je suggérerais de regarder Apache Log4cxx . Ce n'est pas une petite bibliothèque, mais elle supporte à peu près tout ce que vous avez toujours voulu (y compris certaines choses que vous ne saviez même pas que vous vouliez) dans la journalisation, et elle est portable.

Dans tout projet plus important, tôt ou tard, vous voudrez que votre solution de journalisation fasse plus que "une classe de petits enregistreurs", alors pourquoi réinventer la roue?.

2
Joris Timmermans

Cette question a ma tentative avec une certaine fantaisie. C'est complètement C++ Standard et ne fait aucune hypothèse de plate-forme. Il consiste essentiellement en un objet temporaire utilisé comme ceci:

Debug(5) << "This is level 5 debug info.\n";

Je suis sûr que vous pouvez comprendre comment spécifier différents fichiers et d'autres éléments lorsque vous avez la disposition de base. J'ai essayé de garder la classe structurée de telle sorte que dans une version release, chaque forme de sortie Debug soit supprimée aussi bien que possible.

Attention: si vous spécifiez un nom de fichier chaque fois que vous le construisez, ouvrez le fichier et le fermez à nouveau, les performances en souffriront. Dans le cas de plusieurs fichiers de sortie, il serait certainement préférable d'avoir plusieurs membres de données statiques qui ouvrent les différents fichiers lors de l'exécution du programme ou s'ils sont ouverts pour la première fois.

1
rubenvb

Moi aussi, comme beaucoup d’autres, avons également répondu à cette question avec un code.

Ce n'est pas vraiment "prêt" à tous égards, mais il pourrait être facilement modifié:

https://Gist.github.com/earonesty/977b14c93358fe9b9ee674baac5d42d7

Caractéristiques:

  • l'écriture dans le journal ne bloque pas sur les entrées/sorties
  • macros similaires à d'autres solutions (LOGE(blah << stream))
  • préfère rejeter les entrées de journal au ralentissement
  • rinçage paresseux
  • en-tête uniquement, très petit, classes stl uniquement
  • testé sur osx/win/nix
  • le format de l'heure est configurable

Truc manquant:

  • formatage simple et flexible des journaux (prédéfinir une macro conviendrait)
  • les déclencheurs ont une interface mais ne fonctionnent pas encore
  • les microsecondes ne fonctionnent pas encore

Si quelqu'un aime réellement cette solution de quelque manière que ce soit, lmk et je vais en faire un véritable dépôt avec des tests, etc. C'est assez rapide. Probablement pas aussi rapide que speedlogger (une bibliothèque complète plus lourde), mais pas sûr.

0
Erik Aronesty

Une mise à jour de "Un enregistreur léger pour C++" de Dr. Dobb: Il y a en fait deux enregistreurs mentionnés dans celle de Dr. Dobb. Le premier Logging In C++ qui est répertorié dans l’une des réponses. J'ai essayé d'utiliser celui-ci mais la source n'est plus disponible sur le site de Dr. Dobb.

Le deuxième qui a fonctionné pour moi et que je recommande est Un enregistreur léger pour C++ par Filip Janiszewski travaillant chez Nokia Siemens Networks. Au début, j'avais quelques problèmes pour faire fonctionner ce code, alors que je cherchais des solutions, je suis tombé sur une mise à jour de l'auteur original à l'adresse: GitHub: fjanisze/logger . J'ai trouvé ce code facile à comprendre, à modifier et à utiliser. Il est thread-safe et fonctionne avec Visual Studio avec Windows.

Un autre enregistreur mentionné ci-dessus est easylogging ++ . Quand j'ai essayé pour la première fois celui-ci, cela semblait prometteur. Mais lorsque j'ai ajouté threading et sockets2 sous Windows, il s'est écrasé. J'avais le jeu défini pour le threading et Sock2 mais je ne pouvais toujours pas le faire fonctionner donc je ne peux pas le recommander. Le code source est également très complexe, je n’ai donc pas eu la possibilité de le modifier et de le corriger dans un délai raisonnable.

0
Gary G.