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 :

Ajout macros __FILE__ et __LINE__ dans message syslog


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2014
    Messages : 29
    Par défaut Ajout macros __FILE__ et __LINE__ dans message syslog
    Bonjour,

    Jusque là pour suivre le déroulement d'un code, j'utilise un affichage avec des printf avec la macro msg() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    int pmesg(int level, int service, char* format, ...);
     
        #define msg(...) do{if(pmesg(__VA_ARGS__)) fprintf(stderr, " (%s, line %d, %s)\n", __FILE__, __LINE__, __func__);} while(0)
    Maintenant, je souhaiterai ne plus utiliser les fonctions printf mais syslog de linux. J'ai réussi à utiliser syslog et vsyslog dans pmesg(), mais je ne vois pas comment récupérer __VA_ARGS__ et les macros __FILE__, __LINE__ pour générer un affichage syslog sur une même ligne.

    En deux fois :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    int pmesg(const char *file, int line, int level, int service, char* format, ...);
     
    #define msg(...) do{pmesg(__FILE__, __LINE__, __VA_ARGS__);} while(0)
     
     
    int pmesg(const char *file, int line, int level, int service, char* format, ...) {
            //...
            va_start(args, format);
            syslog(LOG_LOCAL0|LOG_DEBUG, "message de test %s %d", file, line);
            vsyslog(LOG_LOCAL0|LOG_NOTICE, format, args);
            va_end(args);
            //...
    }
    Auriez-vous une idée pour concaténer les deux parties du message ?
    Merci

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 828
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 828
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par vincenet Voir le message
    Auriez-vous une idée pour concaténer les deux parties du message ?
    Bonjour

    A tout hasard, sprintf() pour "construire" un nouveau format en utilisant les deux premiers
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char reformat[1024];
    sprintf(reformat, "message de test %%s %%d %s", format)
    syslog(LOG_LOCAL0|LOG_DEBUG, reformat, file, line, args);
    Et si sprintf() n'accepte pas les "%" situés dans le champ "format" alors utiliser strcpy() + strcat()...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2014
    Messages : 29
    Par défaut
    J'aurai souhaité ne pas créer une variable locale pour la chaîne et devoir contrôler les dépassements, mais dans le principe ça marche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
            char reformat[1024];
            char tailformat[256];
            sprintf(tailformat, " (%s, line %d)", file, line);
            va_start(args, format);
            vsprintf(reformat, format, args);
            strcat(reformat, tailformat);
            syslog(LOG_LOCAL0|LOG_DEBUG, reformat);
            va_end(args);
    Plus qu'à utiliser les versions limitant le nombre de caractères pour les fonctions printf (vsnprintf() au lieu de vsprintf() ...).
    Ce qui donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #define MSG_SIZE 10
    #define TAIL_SIZE 10
            va_start(args, format);
            char reformat[MSG_SIZE+TAIL_SIZE];
            char tailformat[TAIL_SIZE];
            snprintf(tailformat, TAIL_SIZE, " (%s, line %d)", file, line);
            if(vsnprintf(reformat, MSG_SIZE+TAIL_SIZE, format, args) < MSG_SIZE+TAIL_SIZE)
            {
                    strncat(reformat, tailformat, MSG_SIZE+TAIL_SIZE);
            }
            syslog(LOG_LOCAL0|LOG_DEBUG, reformat);
            va_end(args);
    Je vous laisse ajuster la taille des tableaux ;-)

  4. #4
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Tu pourrais faire directement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    vsyslog(LOG_LOCAL0|LOG_DEBUG, "message de test %s %d : " format, file, line, args);
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2014
    Messages : 29
    Par défaut
    Citation Envoyé par dinobogan Voir le message
    Tu pourrais faire directement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    vsyslog(LOG_LOCAL0|LOG_DEBUG, "message de test %s %d : " format, file, line, args);
    L'idée me séduit, as-tu bien vu ça dans un code C ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    myLib.c: In function 'pmesg':
    myLib.c:173:66: error: expected ')' before 'format'
             vsyslog(LOG_LOCAL0|LOG_DEBUG, "message de test %s %d : " format, file, line, args);
                                                                      ^
    myLib.c:173:66: error: too few arguments to function 'vsyslog'
    In file included from /home/vincent/oe_daisy/oecore/sysroots/armv5te-oe-linux-gnueabi/usr/include/syslog.h:1:0,
                     from myLib.h:16,
                     from myLib.c:4:
    /home/vincent/oe_daisy/oecore/sysroots/armv5te-oe-linux-gnueabi/usr/include/sys/syslog.h:200:13: note: declared here
     extern void vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap)

  6. #6
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Citation Envoyé par vincenet Voir le message
    L'idée me séduit, as-tu bien vu ça dans un code C ?
    arf.... j'ai écrit trop vite sans vérifier et en lisant la question en diagonale...
    J'ai développé une librairie de log utilisée sur plusieurs projets. Je passe par ma fonction intermédiaire et ensuite une chaine de 1 Ko pour construire la ligne de log.
    C'est ma fonction de log qui est utilisable comme ça donc c'est assez éloigné de ta question initiale

    Mais le principe de base dans ma librairie est d'utiliser les MACRO. Exemple :
    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
    #include <stdlib.h>
    #include <stdio.h>
    #include <stdarg.h>
     
    #define CHAINE_GEANTE 2048
     
    void mon_log( char * format, ... )
    {
        va_list args;
        va_start( args, format);
        vprintf( format, args );
        va_end( args );
    }
     
    #define INFO_LOG( format, ar... ) mon_log( "ligne %d, fonction %s : "format"\n", __FILE__, __FUNCTION__, ##ar )
     
    int main()
    {
        INFO_LOG( "salut %d, ca roule ? %s", 56, "hello" );
        char chaine[] = "coucou";
        INFO_LOG( "%s", chaine );
        exit( 0 );
    }
    Il faut passer par une macro et une fonction.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Ça manque un peu de polyvalence, tu devrais toujours faire la version v:
    Code C : 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
    #include <stdlib.h>
    #include <stdio.h>
    #include <stdarg.h>
     
    #define CHAINE_GEANTE 2048
     
    void mon_logv( char const * format, va_list args )
    {
        vprintf( format, args );
    }
     
    void mon_log( char const * format, ... )
    {
        va_list args;
        va_start( args, format);
        mon_logv(format, args);
        va_end( args );
    }
     
    #define INFO_LOG( format, ar... ) mon_log( "ligne %d, fonction %s : "format"\n", __FILE__, __FUNCTION__, ##ar )
     
    int main()
    {
        INFO_LOG( "salut %d, ca roule ? %s", 56, "hello" );
        char chaine[] = "coucou";
        INFO_LOG( "%s", chaine );
        exit( 0 );
    }
    Aussi, c'est mieux d'accepter des pointeurs const quand on ne modifie pas le contenu.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ça manque un peu de polyvalence, tu devrais toujours faire la version v:

    Aussi, c'est mieux d'accepter des pointeurs const quand on ne modifie pas le contenu.
    C'est ce que j'ai fait dans ma librairie
    Le code posté était juste pour donner l'idée et exprimer à quel point mon intervention était à côté de la plaque sur la question initiale
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2014
    Messages : 29
    Par défaut
    Bonjour et merci pour les réponses.

    Cependant, cela ne m'apprend pas grand chose car il manque les paramètres dans vos exemples : le niveau d'importance du message "int level" et le service concerné "int service".

    Donc voilà où j'en suis en essayant de coller à votre proposition :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    msg(ERROR, MSG_JEU, "file path:%s does it exist ?", res); // exemple d'appel (que je ne souhaite pas changer)
    macro et prototype :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #define msg(...) my_log(format" ligne %d, fonction %s", __VA_ARGS__, __FILE__, __FUNCTION__ )   
     
     
    int my_log(int level, int service, char* format, ...);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    myLib.h:58:31: error: too few arguments to function 'my_log'
     #define msg(...) my_log(format" ligne %d, fonction %s", __VA_ARGS__, __FILE__, __FUNCTION__ )
                                   ^
    jeu.c:1037:13: note: in expansion of macro 'msg'
                 msg(ERROR, MSG_JEU, "file path:%s does not exist", res);
                 ^

  10. #10
    Invité
    Invité(e)
    Par défaut
    Bonsoir,

    Pour commencer,
    Citation Envoyé par vincenet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define msg(...) my_log(format" ligne %d, fonction %s", __VA_ARGS__, __FILE__, __FUNCTION__ )
    où est cette entrée format ?
    Ensuite, tu définis ta fonction my_log comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int my_log(int level, int service, char* format, ...);
    qu'as-tu fait des paramètres level et service ?

    Les trois points dans msg(...) sont reportés à l'endroit où tu mets __VA_ARGS__, ce qui donne avec ton appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    msg(ERROR, MSG_JEU, "file path:%s does it exist ?", res);
    // =>
    my_log(<non défini>" ligne %d, fonction %s", ERROR, MSG_JEU, "file path:%s does it exist ?", res, __FILE__, __FUNCTION__ )
    //                                          [----------------- __VA_ARGS__ ---------------------]
    ils ne vont pas miraculeusement s'éparpiller selon tes désirs.

    Rajoute donc les paramètres level, service et format dans ta macro, comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define msg(level, systeme, format, ...) my_log(level, systeme, format" ligne %d, fonction %s", __VA_ARGS__, __FILE__, __FUNCTION__ )
    Au passage un const sur le paramètre format ne ferait pas de mal.
    Dernière modification par Invité ; 09/12/2014 à 18h49. Motif: typo

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2014
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2014
    Messages : 29
    Par défaut
    Merci.

    J'ai simplement ajouté les ## et une virgule avant les ... dans la macro et je pense avoir compris le principe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define msg(level, service, format, ...) my_log(level, service, format" (ligne %d, file %s)", ##__VA_ARGS__, __LINE__, __FILE__ )
    Ma question initiale est donc résolue.

    Petite question bonus pour la gymnastique avec format et __VA_ARGS__

    Dans la fonction mon_log(), l'affichage se fait finalement avec syslog :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            vsyslog(LOG_LOCAL0|LOG_DEBUG, format, args);
    J'aimerai ajouter deux valeurs dans l'affichage (numéro du message et les millisecondes du temps courant). Je lai fait dans un premier temps en concaténant format avec une deuxième chaîne via les fonctions vsnprintf, snprintf et strncat et des buffers. Y aurait-il moyen d'éviter ces appels et buffers avec le principe de manipuler format et __VA_ARGS__ ?

    Deuxième interrogation, si je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	    msg(WARNING, MSG_XML, "une chaine : ", path); // %s manquant
    Je n'ai aucun warning à la compilation :-(

Discussions similaires

  1. Macro : Extraire une donnée dans un message
    Par roidurif dans le forum Macros et VBA Excel
    Réponses: 0
    Dernier message: 04/04/2011, 13h15
  2. ajout macro complémentaire dans menu
    Par spidtrip dans le forum VBA PowerPoint
    Réponses: 0
    Dernier message: 06/07/2010, 15h12
  3. Ajouter macro dans document word
    Par ac/dc dans le forum C#
    Réponses: 4
    Dernier message: 14/11/2008, 17h25
  4. Ajout d'une case à cocher dans un message box
    Par Jahjouh dans le forum MFC
    Réponses: 1
    Dernier message: 31/08/2007, 11h46

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