Partage
  • Partager sur Facebook
  • Partager sur Twitter

Logger avec stream

    17 avril 2018 à 21:05:52

    Salut,

    Je développe un logiciel et j'aimerais écrire un petit logger pour gérer les niveaux d'affichage.
    J'ai trouvé plusieurs codes en ligne, mais aucun ne fait vraiment ce que je veux. L'un d'entre eux par exemple utilise une macro pour comparer le niveau du logger et celui de message, mais si je peux me passer de macros, j'aimerais autant.

    J'ai écrit une version très simple pour me familiariser avec le truc :

    #ifndef LOGGER_H
    #define LOGGER_H
    
    #include <iostream>
    
    enum Level {ERROR = 0, WARNING, INFO, DEBUG, DEBUG1, DEBUG2, DEBUG3, DEBUG4};
    
    class Logger {
        public:
            const static Level logger_level = INFO;
    };
    
    template <typename T>
    Level operator<< (Level level, T& element) {
        if (level >= Logger::logger_level) {
            std::cerr << element; // aie, c'est en dur
        }
        return level;
    }
    
    #endif // LOGGER_H

    Et pour le moment je l'utilise comme ceci :

    DEBUG << "Creating the optimization problem\n";

    ce qui est un peu bizarre. J'aimerais un truc dans le genre :

    Logger::cerr(DEBUG) << "Creating the optimization problem\n";

    Mais je ne sais pas comment gerer le stream de sortie + le niveau du message.
    Ça vous inspire ?
    Merci,

    Charlie

    • Partager sur Facebook
    • Partager sur Twitter
      17 avril 2018 à 23:22:10

      Salut, Tu peux mettre ton level dans le ctor. Tu peux utiliser des templates pour tes level. Tu peux stocker des messages dans ton logger et les afficher plus tard etc ...

      Je comprends pas trop le résultat que tu veux, ce serait pas plus pratique d'avoir le nom du level dans l'appel de ta fonction ?

      Logger::debug() << "Message";

      Après des macros c'est pratique aussi : mylib_info &lt;&lt; "msg"; mylib_debug etc ... Et ça te permet de modifier ton logger si besoin.

      Edit: Tu veux définir ton level dans ta classe en fait ? En général on utilise une macro pour ça pour pouvoir définir le niveau des logs à la compilation. C'est pas pratique d'aller modifier une classe juste pour ça. C'est quoi que tu n'arrives pas à faire exactement ?

      -
      Edité par ads00 17 avril 2018 à 23:26:38

      • Partager sur Facebook
      • Partager sur Twitter
        17 avril 2018 à 23:32:14

        Merci pour ta réponse.
        Je n'ai pas précisé : je n'ai pas envie que le logger soit une variable globale (parce que j'ai horreur de ça :lol:), c'est pour ça que j'ai tout fait en statique (pas de constructeur, du coup). Après si c'est complètement débile...

        Logger::debug() << "Message";
        Ca me va, mais on ne peut pas choisir le stream du coup. Apres, si le stream est toujours std::cerr, ca simplifie les choses.
        Quelle serait la signature de debug() ? Je ne pense pas qu'elle puisse renvoyer un ostream (dans le cas ou le message n'est pas affiché, il faudrait renvoyer un stream vide. Je ne sais pas si c'est possible).


        -
        Edité par cvanaret 17 avril 2018 à 23:36:40

        • Partager sur Facebook
        • Partager sur Twitter
          17 avril 2018 à 23:41:19

          En fait je saisis pas trop ton système de logs. Tu veux cout pour les info/warning/debug et cerr pour les erreurs ? Si tu as une fonction nommée par type de log je vois pas de problème.

          • Partager sur Facebook
          • Partager sur Twitter
            17 avril 2018 à 23:53:23

            Admettons que que c'est toujours cerr, quel que soit le type du message.

            Certains messages ne doivent pas être affichés, puisque leur niveau n'est pas suffisant par rapport au niveau du logger. Comment gérer ça autrement que par des macros ?
            • Partager sur Facebook
            • Partager sur Twitter
              18 avril 2018 à 0:11:27

              Avec un check comme tu l'as fait. Je vois pas trop pourquoi il y aurait des macros.

              Mais tu devrais construire ton message de log avant de le filer au logger en surchargeant <<

              Tu fais un objet log_message qui surcharge << puis ton logger prend ce log_message en paramètre. Et ton logger check si il doit affiché le message ou pas.

              -
              Edité par ads00 18 avril 2018 à 0:13:02

              • Partager sur Facebook
              • Partager sur Twitter
                18 avril 2018 à 15:51:53

                Je pense comprendre ce que tu veux dire...
                En gros, tu voudrais que dans ce code :
                Logger::debug() << "Log n°" << i << "\n";

                je crée d'abord le message du genre "Log n°2\n", puis que je le file au logger ?
                Si c'est bien ça, << est associatif à gauche, donc c'est équivalent à :

                ((Logger::debug() << "Log n°") << i) << "\n";

                Du coup, je ne vois pas du tout :honte:
                • Partager sur Facebook
                • Partager sur Twitter
                  18 avril 2018 à 18:42:32

                  Soit tu mets des parenthèses, soit tu utilises un autre opérateur puis une macro. Je t'ai fait un exemple : http://cpp.sh/6k63f Ensuite tu rajoutes tes levels et tes conditions d'affichage du message comme tu veux.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    18 avril 2018 à 23:07:37

                    Ce qui est dommage avec la condition dans le logger, c'est que les paramètres du message doivent être construit. Lorsqu'ils sont juste récupérés de variable déjà existant le coût est proche de 0, mais lorsque qu'il faut construire la valeur pour ensuite ne pas l'afficher, on se retrouve à faire du travail inutile.

                    On peut aussi vouloir ajouter le nom de la fonction/classe, du fichier et son numéro de ligne (au moins pour le debug). Sans macro, le message pourrait ressembler à:

                    if (level_debug >= logger_level) {
                      Logger::debug(__PRETTY_FUNCTION, __FILE__, __LINE__) << "Log n°" << i;
                    }
                    

                    Ce qui n'est pas franchement agréable à écrire.

                    Alors qu'avec une macro, on peut avoir quelque chose proche de LOG(level, "Log n°", i);

                    #define LOG(level, ...) do {
                      if (level >= logger_level) {
                        [](auto const&... xs){ Logger::level(__PRETTY_FUNCTION, __FILE__, __LINE__) << ... << xs; }(__VA_ARG__);
                      }
                    } while (0)
                    
                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 avril 2018 à 15:31:52

                      Merci les gars, je regarde ça rapidement :)
                      • Partager sur Facebook
                      • Partager sur Twitter

                      Logger avec stream

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown