2010-10-14 4 views
0

Je voudrais utiliser un gestionnaire de msg erreur générique, donc je peux facilement GetLastError et SetError facilement pour toute classe. Je suis venu avec ce régime. Mais j'ai quelques questions. Veuillez noter que cette implémentation est juste pour tester. Mais je veux que le design de base soit correct.Comment ajouter un enregistreur d'erreurs à une classe

#include <iostream> 
#include <stdarg.h> 

class ErrorHandler 
{ 
    public: 
     virtual void SetError(const char* zFormat, ...) 
     { 
      va_list args; 
      va_start (args, zFormat); 
      vsnprintf (z_ErrorBuf, sz_MaxBufSize, zFormat, args); 
      va_end (args); 
     } 

     const char* GetError() const 
     { 
      return z_ErrorBuf; 
     } 

     virtual ~ErrorHandler(){} 

     explicit ErrorHandler(const size_t szMaxBufSize = 1024) 
     { 
      z_ErrorBuf = malloc(sizeof(char)*szMaxBufSize); 
      sz_MaxBufSize = szMaxBufSize; 
     } 

     void ResizeBuffer(const size_t szMaxBufSize) 
     { 
      z_ErrorBuf = realloc(z_ErrorBuf, szMaxBufSize); 
      sz_MaxBufSize = szMaxBufSize; 
     } 

    protected: 
     char* z_ErrorBuf; 
     size_t sz_MaxBufSize; 
}; 

class MyClass; 

//Worker can be just an interface if needed. So, can't use friend. 
class Worker 
{ 
    public: 
     void Work(MyClass& oGod); 
}; 

void Worker::Work(MyClass& oGod) 
{ 
    //Work 
    //OnError 
    oGod.GetErrorHandler().SetError("Save me %s", "not"); 
} 

class RecordingErrors 
{ 
    public: 
     const char* GetLastError() const 
     { 
      return oErrorHandler.GetError(); 
     } 

     //GetErrorHandler is public 
     ErrorHandler& GetErrorHandler() 
     { 
      return oErrorHandler; 
     } 

    private: 
     ErrorHandler oErrorHandler; 
}; 

class MyClass : public RecordingErrors 
{ 
    public: 
     bool GetThingsDone(Worker& me) 
     { 
      me.Work(*this); 

      //on Error 
      return false; 
     } 
}; 

int main() 
{ 
    MyClass oL; 
    Worker w; 
    if(!oL.GetThingsDone(w)) 
    { 
     std::cout << oL.GetLastError() << std::endl; 
    } 
} 
  1. Puis-je remplacer cette fonction dans une classe d'enfants? virtual void SetError(const char* zFormat, ...). Puis-je supprimer la classe RecordingErrors?
  2. Je pense que alors MyClass devrait hériter de ErrorHandler ce que je ne pense pas est bon. Ai-je raison ou tort? Est-ce une autre question sur la composition sur l'héritage. EDIT: Je ne parle pas du nom, mais de l'idée?
  3. Tous les scénarios possibles cette approche échouerait?
  4. est-il une meilleure façon de mettre en œuvre la journalisation des erreurs? (L'enregistrement est pas le mot ici. Qu'est-ce)
+0

Avez-vous envisagé d'utiliser des exceptions? –

+0

Nous vous recommandons explicitement de ne pas utiliser d'exceptions. Et aucun du code que j'ai vu dans mon entreprise. De plus, je n'ai pas d'expérience avec les exceptions et je ne suis pas sûr de savoir comment récupérer une exception ou effectuer un nettoyage correctement. – nakiya

+0

[Herb Sutter] (http://herbsutter.com/) a récemment quelques idées pour la journalisation des erreurs: [Effective Concurrency: Savoir quand utiliser un objet actif au lieu d'un Mutex] (http://www.drdobbs.com/ go-parallel/article/showArticle.jhtml? articleID = 227500074 & pgno = 3) – rwong

Répondre

3

la gestion d'erreurs et enregistreur sont deux entités différentes. Le gestionnaire d'erreurs décide quoi faire avec les erreurs. Devrait-il être envoyé à l'enregistreur immédiatement, devrait-il être sauvegardé dans des bases de données, ou devrait-il être simplement sauvegardé dans un tampon jusqu'à ce que quelqu'un demande. L'enregistreur décide comment enregistrer le message donné. Doit-il être affiché sur la console ou devrait-il être sauvegardé dans le fichier disque, dans quel format il devrait être montré. Gardez à l'esprit les caractéristiques de l'enregistreur.
1) Ce devrait être une classe indépendante. Son comportement ne devrait pas dépendre des autres classes.
2) Logger le plus préférable devrait être singleton. Vous n'avez pas besoin de nombreux objets flottant autour de faire la même chose. Mais alors les classes singleton ont leurs propres maux de tête quand vient le multi-threading. Je sais donc que ce point est discutable.
3) Il doit et doit avoir des capacités de journalisation asynchrone. Cela signifie la mise en œuvre du producteur et du consommateur. (La journalisation est une opération d'E/S et donc coûteuse dans la nature.Vous ne voulez pas que votre traitement principal monopolise pour cela.) Mais encore une fois, vous ne voudrez pas utiliser des threads pour éliminer celui-ci.)

error logger Je ne peux pas voir d'enregistreur. Votre gestionnaire d'erreur enregistre également une seule erreur. Vous pourriez avoir besoin du vecteur d'erreurs. Conservez SetError avec des arguments fixes. Passez des arguments tels que l'identifiant d'erreur, le message d'erreur et la longueur du tampon d'erreur. Laissez l'appelant créer le message d'erreur.

+0

Non pertinent à ma question :(bien que vos pointeurs sont bons. Comme je l'ai mentionné dans la question, je ne pouvais pas penser à la formulation correcte. veux la dernière erreur Comme 'getlasterror()' – nakiya

+1

J'ai finalement réalisé que tu as raison :). Mon problème était que j'ai essayé de gérer la gestion des erreurs et la journalisation des erreurs en même temps. – nakiya

+0

+1 information très utile. La pile d'appels peut également être utile, et parfois elle est requise par le projet. Avec la journalisation asynchrone (mise en mémoire tampon activée), elle doit décider si les messages doivent être envoyés à l'E/S. Sans rinçage, une erreur critique suivie d'une panne peut ne laisser aucun message dans le journal. – rwong

Questions connexes