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 :

Redirection printf vers un buffer glissant de taille limitée


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Invité
    Invité(e)
    Par défaut Redirection printf vers un buffer glissant de taille limitée
    Bonjour,

    Dans une application embarquée, je cherche à envoyer des informations dans un fichier à des fins de log.
    Je ne dois écrire le fichier qu'une fois à l'extinction de l'appareil, afin d'éviter les accès à ma flash. Les informations doivent donc être stockées dans un buffer temporaire, qui sera écrit dans un fichier au moment voulu.
    Bien évidemment, la taille de ce buffer doit être limitée, et les nouvelles informations doivent éjecter les nouvelles lorsque la taille limite est atteinte (à la façon d'un terminal, dont l'historique le plus ancien est perdu).

    Je cherche le moyen le plus simple et efficace d'envoyer ces informations vers un buffer.
    Je pense rediriger la sortie standard vers un flux. Mais peut-on assigner un flux à un buffer de type FIFO qui se viderait automatiquement lorsqu'elle atteint une certaine taille?

    Merci à vous pour vos idées!

  2. #2
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Tu peux regarder ce que fait log4cpp, qui permet de limiter la taille du fichier de sortie.

    Une solution souple (simple à utiliser) mais pas forcément simple à écrire pourrait être d'écrire une classe servant de buffer à ostream.
    doc de basic_streambuf

    ostream possède un constructeur acceptant un basic_streambuf comme argument. (et le transmettant à basic_ios)

  3. #3
    Invité
    Invité(e)
    Par défaut
    Merci pour cette réponse rapide.

    Je cherche à faire quelque chose de beaucoup moins évolué que log4cpp, mais je suppose que c'était juste pour regarder comment est implémentée la limite de taille.

    La deuxième solution semble la plus adaptée mais elle ne réponds pas encore totalement à mon problème.
    J'aurais pu utiliser snprintf pour écrire dans un buffer circulaire, mais je voulais éviter l'écriture du code gérant ce buffer.

    J'espérais qu'en C++ il existe un conteneur de la STL qui soit capable du comportement cité précédemment: conteneur de capacité limité donc les vieilles données sont jetées lors du dépassement de capacité à l'ajout d'une nouvelle données.
    Est-ce que ce genre de conteneur existe?

  4. #4
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Non, pas que je sache. Par contre il y en a un dans boost (circular_buffer.

    La grosse question, c'est comment gérer la granularité de suppression (ligne à ligne, j'imagine) par rapport à celle de la taille (en nombre d'octets).

    A priori, j'utiliserai endl/flush pour déclencher l'épuration des plus vieilles lignes.
    il doit y avoir un algorithme qui va bien (probablement find avec '\n')

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par simontlr Voir le message
    J'espérais qu'en C++ il existe un conteneur de la STL qui soit capable du comportement cité précédemment: conteneur de capacité limité donc les vieilles données sont jetées lors du dépassement de capacité à l'ajout d'une nouvelle données.
    Est-ce que ce genre de conteneur existe?
    Il n'y a rien de la sorte de manière standard, mais il reste assez facile de limiter la taille de n'importe quel conteneur à l'aide d'un simple test qui prendrait la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if(leConteneur.size() > tailleMax){
        retirer l’excédent pour ne plus dépasser la limite
    }
    A la limite, une simple string pourrait parfaitement faire l'affaire sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    std::string logCache;
    logCache += "Entree a rajouter dans le log";
    if (logcache.size() > maxTaille){
        logCache = logCache.substr(logCache.size() - maxTaille);
        //veille à supprimer toute la ligne (on supprime jusqu'au premier retour à la ligne)
        size_t found = logCache.find("\n");
        if (foudn != std::string::npos){
            logCache = logCache.substr(found);
        }
    }
    // et quand il s'agit d'enregistrer le log
    std::ofstream ofs("leLog.log");
    if(ofs)
        ofs<<logCache;
    Tu peux, bien sur, parfaitement envisager de créer un classe qui agira de la sorte, sous une forme proche de
    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
    class MaxSizeLog{
        public:
            MaxSizeLog(std::string const & filename, size_t maxSize):filename_(filenam),maxSize_(maxSize){
            }
            ~MaxSizeLog(){
                // on considère que l'instance de cette classe est créée dans la fonction main, avant toute autre chose) 
                // et qu'elle sera donc détruite juste avant le "return" final... Nous sommes peut etre face à l'un des cas
                // particulier dans lequel une variable globale peut s'avérer intéressante vu que l'instance 
                // de la classe doit être réellement accessible "depuis partout" ;)
                // 
                // on doit enregistrer le log lorsque l'instance de la classe est détruite
                std::ofstream ofs(filename);
                if (ofs){
                    ofs<< str_;
                }
            }
            MaxSizeLog & operator +=(std::string const & toadd){
                str_+= toadd;
                logCache = logCache.substr(logCache.size() - maxSize_);
                //veille à supprimer toute la ligne (on supprime jusqu'au premier retour à la ligne)
                size_t found = logCache.find("\n");
                if (foudn != std::string::npos){
                    logCache = logCache.substr(found);
                }
            }
        private:
            std::string str_; // ce qui sera écrit dans le log
            std::string filename_; // le nom du fichier log à utiliser
            size_t maxSize_; // la taille du fichier à ne pas dépasser
    };
    NOTA: C'est du code très vite écrit et absolument pas testé, mais l'idée générale est bel et bien là
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    J'avais pas eu le courage de l'écrire

  7. #7
    Invité
    Invité(e)
    Par défaut
    C'est effectivement l'option que j'avais choisie en attendant de trouver quelque chose de plus élégant.
    (concaténation dans un std::string puis réduction de sa taille)

    Je pensais pouvoir éviter d'exécuter "tout ce code" à chaque fois que je rajoute une ligne dans le log, mais apparemment je vais devoir passer par là.

    Merci pour votre aide.

  8. #8
    Invité
    Invité(e)
    Par défaut
    Petite précision par rapport à ton code koala01, même si:
    Citation Envoyé par koala01 Voir le message
    NOTA: C'est du code très vite écrit et absolument pas testé, mais l'idée générale est bel et bien là
    Il faudra veiller à rendre les méthodes atomiques dans le cas d'un programme multi-thread, au risque de voir les tests de taille s'exécuter pendant l'ajout de d'autres données.

  9. #9
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par simontlr Voir le message
    Il faudra veiller à rendre les méthodes atomiques dans le cas d'un programme multi-thread, au risque de voir les tests de taille s'exécuter pendant l'ajout de d'autres données.
    L'avantage, c'est que je l'ai bien précisé : ce code n'est qu'un exemple qui permet de comprendre l'idée générale .

    Déjà, l'opérateur += en fait en réalité beaucoup trop et ne respecte absolument pas le SRP (il ne devrait rien faire d'autre que d'ajouter la ligne de log ).

    Par contre, l'opération peut parfaitement ne pas être atomique! il "suffit" que les chaines à rajouter soient placées dans une "event queue" avant l'opération finale de concaténation, et le problème se résout "tout seul"
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

Discussions similaires

  1. redirection de la commande printf vers un fichier
    Par carvi dans le forum Langage
    Réponses: 5
    Dernier message: 10/07/2008, 09h56
  2. Redirection de printf vers un label
    Par Beavis dans le forum GTK+ avec C & C++
    Réponses: 7
    Dernier message: 02/04/2008, 14h25
  3. [Servlets] Redirection HTTP vers une url absolue
    Par Dinaïz dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 18/11/2005, 21h56
  4. Réponses: 1
    Dernier message: 04/04/2005, 11h19
  5. [ SERVLET ] [JSP ] Redirection servlet vers JSP
    Par Enfa dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 23/02/2005, 14h55

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