2009-12-09 6 views
7

Je souhaite implémenter une classe simple pour la journalisation à partir de plusieurs threads. L'idée est que chaque objet qui veut enregistrer des données reçoit un objet ostream auquel il peut écrire des messages en utilisant les opérateurs habituels. Le comportement souhaité est, que les messages sont ajoutés au journal lorsque le flux est vidé. De cette façon, les messages ne seront pas interrompus par les messages d'autres threads. Je veux éviter d'utiliser une chaîne de caractères temporaire pour stocker le message, car cela ferait au moins la plupart des messages twoliners. Comme je le vois, la façon standard d'y parvenir serait de mettre en place mon propre destroyer, mais cela semble très lourd et sujet aux erreurs. Existe-t-il un moyen plus simple de faire cela? Si non, connaissez-vous un bon article/guide/guide sur les streambufs personnalisés?Journalisation Threadsafe

Merci à l'avance,

Space_C0wbo0y

MISE À JOUR:

Comme il semble fonctionner, j'ai ajouté ma propre réponse.

+0

Cela semble être une bonne solution! Peut-être l'ajouter comme votre propre réponse? –

Répondre

1

Alors, je pris un coup d'œil à Boost.IOstreams et voici ce que je suis venu avec:

class TestSink : public boost::iostreams::sink { 
public: 
    std::streamsize write(const char * s, std::streamsize n) { 
     std::string message(s, n); 
      /* This would add a message to the log instead of cout. 
       The log implementation is threadsafe. */ 
     std::cout << message << std::endl; 
     return n; 
    } 
}; 

TestSink peut être utilisé pour créer un flux tampon (voir stream_buffer-template). Chaque thread recevra sa propre instance de TestSink, mais tous les TestSinks écriront dans le même journal. TestSink est utilisé comme suit:

TestSink sink; 
boost::iostreams::stream_buffer<TestSink> testbuf(sink, 50000); 
std::ostream out(&testbuf); 

for (int i = 0; i < 10000; i++) 
    out << "test" << i; 

out << std::endl; 

Le fait important est ici, que TestSink.write n'est appelée lorsque le flux est rincé (std::endl ou std::flush), ou lorsque la mémoire tampon interne de l'instance stream_buffer est pleine (le tampon par défaut la taille ne peut pas contenir 40000 caractères, donc je l'initalise à 50000). Dans ce programme, TestSink.write est appelé exactement une fois (la sortie est trop longue pour être affichée ici). De cette façon, je peux écrire un message en utilisant des flux-IO formatés normaux sans variables temporaires et être sûr que le message est enregistré dans le journal en une seule fois lorsque je vide le flux.

Je vais laisser la question ouverte un autre jour, au cas où il y aurait différentes suggestions/problèmes que je n'ai pas pris en compte.

5

Jetez un oeil à log4cpp; ils ont un support multi-thread. Cela peut vous faire gagner du temps.

+0

Merci pour votre réponse. Cependant, en raison de la restriction de mon environnement de travail, je ne peux pas introduire une nouvelle bibliothèque. En outre, la plupart des bibliothèques de journalisation existantes sont beaucoup trop lourdes pour mes fins. –

+0

Si vous recherchez une licence plus libérale, consultez Log4cxx d'Apache. http://logging.apache.org/log4cxx/index.html –

0

Re. votre propre réponse. Si vous utilisez cette fonction pour la journalisation des erreurs et que vous programmez des plantages avant de vider votre flux, la journalisation est un peu inutile, n'est-ce pas?

+1

Je suppose que ce serait un problème avec toute approche de journalisation. –

+0

Sauf pour les systèmes de journalisation comme ETW qui ont une aide extérieure. – VoidStar

1

Vous pensez que log4cpp est trop lourd et que vous utilisez plutôt Boost.IOStreams? Huh? Vous pouvez envisager logog. Il est compatible avec les threads pour POSIX, Win32 et Win64.

+0

Si boost est déjà dans son jeu de bibliothèques, alors ce n'est pas si lourd.Sinon, totalement d'accord avec vous. – John