IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Créer Class Logger


Sujet :

C++

  1. #1
    Membre confirmé
    Inscrit en
    Mars 2006
    Messages
    120
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 120
    Par défaut Créer Class Logger
    Bonjour à tous

    Je cherche à créer une classe qui me permettrait d'écrire dans un fichier externe à mon application.
    Je me suis inspiré de celle que crée Laurent Gomilla dans Yes::Engine mais celle-ci est un singleton. Or je souhaite pouvoir créer et écrire dans plusieurs fichiers à différents moments de mon application.
    Non expert en C++ j'essaie de faire la ma mienne pour progresser. J'ai gardé son idée d'opérator "<<" où par exemple il fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CLoggerFile Logger* = new CLOggerFile("Log.log");
    Logger->setLogger(Logger);
    Logger->Log() << "Quel beau log " <<  " \n";
    Voici ma classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class CMyLogger
    {
    public:
    	CMyLogger(const std::string& Filename = "Output.log");
    	~CMyLogger(void);
     
    template <class T> CMyLogger* operator <<(const T& ToLog);
     
    private:
    	std::ofstream m_File;
    	string filename;
    	void Write(const std::string& Message);
     
    protected :
        std::string CurrentDate() const;
        std::string CurrentTime() const;
     
    };
    et les déclarations :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    CMyLogger::CMyLogger(const std::string& Filename):m_File(Filename.c_str())
    {
    	if (!m_File)
    		printf("Impossible d'accéder en écriture : %s \n",Filename);
     
        // Ecriture de l'en-tête du fichier
        m_File << "  ===========================================" << std::endl;
     
    	filename = Filename;
    }
     
    CMyLogger::~CMyLogger(void)
    {
    }
     
    template <class T> CMyLogger* CMyLogger::operator <<(const T& ToLog)
    {
        std::ostringstream Stream;
        Stream << ToLog;
    	Write(Stream.str());   
    }
     
    std::string CMyLogger::CurrentDate() const
    {
        // Récupération et formatage de la date
        char sTime[24];
        time_t CurrentTime = time(NULL);
        strftime(sTime, sizeof(sTime), "%d/%m/%Y", localtime(&CurrentTime));
     
        return sTime;
    }
     
     
    std::string CMyLogger::CurrentTime() const
    {
        // Récupération et formatage de la date
        char sTime[24];
        time_t CurrentTime = time(NULL);
        strftime(sTime, sizeof(sTime), "%H:%M:%S", localtime(&CurrentTime));
     
        return sTime;
    }
     
    void CMyLogger::Write(const std::string& Message)
    {
        assert(m_File.is_open());
     
        m_File << Message << std::flush;
    }

    Le petit bout de code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    CMyLogger* Logger = new CMyLogger("Kx.log");
    	Logger << "Welcome" << "\n";
    provoque les erreurs sous VC8:
    error C2296: '<<' : illegal, left operand has type 'CMyLogger *'
    error C2297: '<<' : illegal, right operand has type 'const char [9]'

    Pourriez-vous m'indiquer mes erreurs et la bonne direction à prendre svp ?

  2. #2
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 292
    Par défaut
    Si tu veux pouvoir sélectionner ton fichier, abandonnes l'idée d'un singleton.
    Attention aux éventuels problèmes de multithreading
    Idéalement, il faut dériver un streambuf et faire de ta classe visible un ostream.

    Pour ton erreur, tu confonds variable et pointeur d'où l'erreur.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  3. #3
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template <class T> CMyLogger* CMyLogger::operator <<(const T& ToLog)
    {
        std::ostringstream Stream;
        Stream << ToLog;
    	Write(Stream.str());   
    }
    Doit être mise dans le header (pour que tout utilisateur puisse, au besoin, créer le bout de code dont il a besoin).

    Quant à l'opérateur << il s'applique sur un *objet* ... et pas un pointeur...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    CMyLogger* pLogger = new CMyLogger(...);
    *pLogger << ....;
    Pour pouvoir "empiler" les appels à << ( par exemple logger << toto << tata; ) il faut que le premier << renvoit un objet qui définit << !
    En général, c'est lui même donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <class T> CMyLogger& CMyLogger::operator <<(const T& ToLog)
    {
        std::ostringstream Stream;
        Stream << ToLog;
    	Write(Stream.str());   
        return *this;
    }
    A noter que je n'ai pas vérifier l'exactitude du code, juste la sémantique...

  4. #4
    Membre confirmé
    Inscrit en
    Mars 2006
    Messages
    120
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 120
    Par défaut
    Merci Messieurs cela fonctionne à merveille.

    Je ne comprends pas trop pourquoi j'ai besoin de déclarer l'opérateur << dans le header.

    Si vous pouviez m'éclairer ...

  5. #5
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Parcequ'un template n'est pas du code...

    Un peu comme les #XXXX qui sont des instructions au précompilateur, les template disent au compilateur: Si quelqu'un te demande CMyLogger::operator <<(const MonObjet& ToLog), voilà comment générer le code, en faisant correspondre MonObjet et T.

    Tu peux définir 20000 templates, ... si aucun n'est utilisé, aucun code n'est généré....
    A l'inverse, tu peux définir un petit template de 2K, et si tu as 20000 classes différentes de remplacement, tu vas te retrouver avec 40Mo de code...


    Hors... pour que le compilateur sache comment générer le code, il faut, lors de la compilation de ton unité (en général un .cpp) que la définition totale soit connue, et donc, inclue dans un header.

  6. #6
    Membre chevronné
    Avatar de NewbiZ
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2002
    Messages
    184
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2002
    Messages : 184
    Par défaut
    Hello,
    Si ca peut t'aider, je mets ci-dessous ma variante semi-statique de logger.
    C'est assez simple d'utilisation, il n'y a qu'à dériver de Logger et définir une fonction write. Je mets deux exemples pour la forme.
    Ensuite, il ne reste plus qu'à passer une TypeList des loggers à utiliser lors de la déclaration du LoggerHolder.

    Si vous avez des commentaires ou des conseils je suis (comme toujours) preneur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    /**
     * Definition of the Logger interface
     * 
     * @author  Aurélien Vallée <vallee.aurelien@gmail.com>
     * @file    logger.hh
     * @version 1.0
     * @date    lundi 4 février 2008 02:37:40
     */
     
    /**
     * @brief This interface represents a logger
     * 
     * You are free to create loggers for almost any
     * possible output including files, terminals,
     * devices and even network.
     */
     
    #ifndef LOGGER_HH
    #define LOGGER_HH
     
    #include <string>
     
    class Logger
    {
    public:
      virtual ~Logger() {}
     
      virtual void write( const std::string& ) = 0;
    };
     
    #endif // LOGGER_HH
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    /**
     * Definition of the LoggerConsole class
     * 
     * @author  Aurélien Vallée <vallee.aurelien@gmail.com>
     * @file    loggerconsole.hh
     * @version 1.0
     * @date    lundi 4 février 2008 02:37:52
     */
     
    /**
     * @brief This class allows the output to console
     * 
     * The output is directed to stdin via std::cout.
     */
     
    /**
     * @todo Add date & time in constructor ?
     */
     
    #ifndef LOGGERCONSOLE_HH
    #define LOGGERCONSOLE_HH
     
    #include "logger.hh"
    #include "macros.hh"
    #include <iostream>
     
    FF_CORE_BEGIN
     
    class LoggerConsole : public Logger
    {
    public:
      virtual void write( const std::string& msg )
      {
        std::cout << msg;
      }
    };
     
    FF_CORE_END
     
    #endif // LOGGERCONSOLE_HH
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    /**
     * Definition of the LoggerFile class
     * 
     * @author  Aurélien Vallée <vallee.aurelien@gmail.com>
     * @file    loggerfile.hh
     * @version 1.0
     * @date    dimanche 17 février 2008 07:49:22
     */
     
    /**
     * @brief <file short description>
     * 
     * <file full description>
     */
     
    /**
     * @todo <todo list>
     */
     
    #ifndef LOGGERFILE_HH
    #define LOGGERFILE_HH
     
    #include "logger.hh"
    #include "macros.hh"
    #include "time/time.hh"
    #include <fstream>
    #include <sstream>
     
    FF_TIME_USE
     
    FF_CORE_BEGIN
     
    class LoggerFile : public Logger
    {
    public:
      LoggerFile()
      {
        file_.open( "output.log", std::ios::app );
     
        file_.seekp( std::ios::beg );
     
        if (!file_.good()) return;
        file_ << "  ===============================================\n"
              << "    Begin Output log ( "
              << Time::getDate()
              << " at "
              << Time::getTime()
              << " ):\n  ===============================================\n\n";
        file_.flush();
      }
     
      virtual ~LoggerFile()
      {
        if (!file_.good()) return;
        file_ << "\n  ===============================================\n"
              << "    End   Output log ( "
              << Time::getDate()
              << " at "
              << Time::getTime()
              << " ):\n  ===============================================\n\n";
        file_.flush();
        file_.close();
      }
     
      virtual void write( const std::string& msg )
      {
        file_ << msg;
        file_.flush();
      }
     
    private:
      std::ofstream file_;
    };
     
    FF_CORE_END
     
    #endif // LOGGERFILE_HH
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    /**
     * Definition of the LoggerHolder class
     * 
     * @author  Aurélien Vallée <vallee.aurelien@gmail.com>
     * @file    loggerholder.hh
     * @version 1.0
     * @date    dimanche 17 février 2008 07:34:22
     */
     
    /**
     * @brief <file short description>
     * 
     * <file full description>
     */
     
    /**
     * @todo <todo list>
     */
     
    #ifndef LOGGERHOLDER_HH
    #define LOGGERHOLDER_HH
     
    #include <list>
    #include <string>
    #include <sstream>
    #include "logger.hh"
    #include "macros.hh"
    #include "types.hh"
     
    FF_CORE_BEGIN
     
    template <class T>
    class LoggerHolder
    {
    private:
      template <class T>
      struct LoggerList : public std::list<Logger*> {};
     
      template <>
      struct LoggerList<NullType> : public std::list<Logger*>{};
     
      template <class H, class T>
      struct LoggerList<TypeList<typename H, typename T>>
        : public std::list<Logger*>
      {
        typedef TypeList<typename H, typename T> List_t;
        typedef typename H Head_t;
        typedef typename T Tail_t;
     
        LoggerList()
        {
          push_back( new Head_t );
          LoggerList<Tail_t> tmp;
          merge( tmp );
        }
     
        ~LoggerList()
        {
          LoggerList<List_t>::iterator it;
          for ( it=begin(); it!=end(); ++it )
            delete *it;
        }
      };
     
      LoggerList<T> loggers_;
     
      template <class U>
      LoggerHolder( const LoggerHolder<U>& lh ){}
      template <class U>
      LoggerHolder<U>& operator=( const LoggerHolder<U>& lh );
     
    public:
      LoggerHolder(){}
      ~LoggerHolder(){}
     
      template <class U>
      LoggerHolder<T>& operator<<( const U& message )
      {
        std::ostringstream oss;
        oss << message;
        for ( LoggerList<T>::iterator it=loggers_.begin();
          it!=loggers_.end();
          ++it )
        {
          (**it).write( oss.str() );
        }
        return *this;
      }
    };
     
    FF_CORE_END
     
    #endif // LOGGERHOLDER_HH
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    /**
     * Definition of unified cross-platform types
     * 
     * @author  Aurélien Vallée <vallee.aurelien@gmail.com>
     * @file    types.hh
     * @version 1.0
     * @date    dimanche 17 février 2008 02:59:47
     */
     
    /**
     * @brief Definition of unified cross-platform types
     * 
     * These typedef aims at avoiding different type sizes
     * between platforms.
     */
     
    /**
     * @todo Handle type size more efficiently (no more asserts)
     */
     
    #ifndef TYPES_HH
    #define TYPES_HH
     
    #include "macros.hh"
     
    // [...]
     
    // Null type
    class NullType {};
     
    // Type list
    template <class H, class T>
      class TypeList
      {
        typedef H Head;
        typedef T Tail;
      };
     
    FF_CORE_END
     
    #endif // TYPES_HH
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #ifndef MACROS_HH
    #define MACROS_HH
     
    // [...]
     
    //------------------------------------------------------------
    // TYPE LISTS
    //------------------------------------------------------------
     
    #define TYPELIST_1(T1)\
    TypeList<T1, NullType>
     
    #define TYPELIST_2(T1, T2)\
    TypeList<T1, TYPELIST_1(T2)>
     
    #define TYPELIST_3(T1, T2, T3)\
    TypeList<T1, TYPELIST_2(T2, T3)>
     
    #define TYPELIST_4(T1, T2, T3, T4)\
    TypeList<T1, TYPELIST_3(T2, T3, T4)>
     
    //------------------------------------------------------------
    // SHORTCUTS
    //------------------------------------------------------------
     
    #define TheApp (FF_GAME ::Application::getInstance())
     
    #endif // MACROS_HH

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. créer classe en fonction de table sqlserver
    Par polux31 dans le forum ASP.NET
    Réponses: 1
    Dernier message: 28/04/2011, 08h41
  2. [log4j] Créer un Logger personnel
    Par El Saigneur dans le forum Logging
    Réponses: 6
    Dernier message: 29/09/2008, 13h08
  3. [précompilation] Class Logger
    Par laclac dans le forum C++
    Réponses: 1
    Dernier message: 31/01/2007, 10h29
  4. [Outils][C#] Comment créer classe à partir table SqlServer ?
    Par Cédric B. dans le forum EDI/Outils
    Réponses: 3
    Dernier message: 19/01/2006, 13h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo