Gestion des messages de log - vos expériences

Bonjour à tous
Je me suis remis à faire un peu de prog en C.
Mon but est en fait de traduire des scripts Perl en langage C.

Je bloque sur un point : la gestion des logs.
Autannt en perl, il est aisé de générer des logd avec Log4Perl, autant en C, je bute sur la construction des messages (en fait les chaines de caractères.

en Perl :

$logger->debug( "Famille :: $familletMaquette :: $maquette");

(concaténation automatique des chaines de caractères)

En C :


//en résumé

#define LOG_INFO(msg) fprintf(fileLog, "%s %sn",getStartMessageForLog(INFO, __LINE__),msg);
#define LOG_WARNING(msg) fprintf(fileLog, "%s %sn",getStartMessageForLog(WARNING, __LINE__),msg);
#define LOG_ERROR(msg) fprintf(fileLog, "%s %sn",getStartMessageForLog(ERROR, __LINE__),msg);
#define LOG_DEBUG(msg) if(DEBUG_ACTIVATED) fprintf(fileLog, "%s %sn",getStartMessageForLog(DEBUG, __LINE__),msg);
....
sprintf( msg, "Famille :: %stMaquette :: %sn", famille, maquette);
LOG_INFO(msg);

En fait, j’aurais voulu créer une fonction qui travaillerait de la sorte :

void printLog( int niveau, char *format, ... );

cad qu’elle agrège les 2 lignes ‘sprintf’ et ‘LOG_INFO’ en une seule, les variables après ‘format’ servent à créer la ligne écrite dans le fichier de log.

Question : comment faire ?
Sachant qu’il faut que la fonction évalue ce que contient la variable format, ça me parait compliqué.

Quelles autres solutions utilisez vous pour la gestion des log en langage C sous windows (autre OS inutile).

Ce que tu cherches, c’est ça : www.cplusplus.com…

Et c’est ainsi que fonctionne printf (le lien c’est du c++ mais ça s’applique aussi au C) : pour chaque format, elle va interpréter le type dans va_arg.

Tu dois pouvoir aussi le faire via une macro et déléguer ça à fprintf ou autre, mais je ne sais pas si ça accepte (enfin?) les var args.

Maintenant, je ne fais pas de C en dehors du monde pro, où c’est du fait maison. Tu as aussi des frameworks de log comme Boost Log v2 : www.boost.org…

Après, si c’est pour un petit projet, l’une ou l’autre des solutions vaut.

j’avais déjà trouvé les va_args, mais je n’avais aucune idée de comment les utliser.

grâce au premier lien, je suis arrivé à unee fonction pas trop dégueulasse :


void printLog(int logLevel, int lineNumber, char *format, ...){
    char buffer[2048];
    va_list args;
    va_start (args, format);
    vsprintf (buffer,format, args);
    va_end (args);
    if( fileLog != NULL){ //fichier de log
        if(logLevel == INFO || logLevel == ERROR || logLevel == DEBUG ||logLevel == WARNING){ //différents niveau dispo
            fprintf(fileLog, "%s%sn", getStartMessageForLog(logLevel, lineNumber), buffer);
        }
    }
}

utilisation :


printLog(DEBUG, __LINE__, "Date de composition :: '%s'", dateLivraison);

j’avais pensé à utiliser des macros mais le premier test n’a fait que complexifier le code.

Je te suggère de déplacer le test, et l’initialisation des va_arg, dans le bloc if (fileLog).
Les macros, c’est surtout pour le numéro de ligne : là, ce que tu fais, ça devient vite pénible.

Tu devrais avoir une macro, genre log, qui ferait ça :

#define log(level, fmt, ...) printLog(_level_, __FILE__, __LINE__, fmt, __VA_ARGS__);

Plus d’informations sur VA_ARGS ici :

msdn.microsoft.com… (VisualStudio)
gcc.gnu.org… (G++)

ta solution fonctionne très bien

une petite erreur de type sur la variable level:

#define _log(_level_, fmt, ...) printLog(_level_, __LINE__, fmt, __VA_ARGS__);

j’ai moi même mis un underscore devant log

la fonction printLog

void printLog(int logLevel, int lineNumber, char *format, ...){
    char buffer[2048];

    if( fileLog != NULL){
        if(logLevel == INFO || logLevel == ERROR || (logLevel == DEBUG && DEBUG_ACTIVATED == 1) || logLevel == WARNING){
            va_list args;
            va_start (args, format);
            vsprintf (buffer,format, args);
            va_end (args);
            fprintf(fileLog, "%s%sn", getStartMessageForLog(logLevel, lineNumber), buffer);
            fflush(fileLog);
        }
    }
}

La variable DEBUG_ACTIVATED est globale, sa valeur est alimenté en fonctiondes paramètres envoyés à l’application (utilisation de getopt_long)

et deux exemples d’utilisation :

_log(ERROR, "Impossible de créer le fichier '%s'", envControle->fichierControle);
_log(INFO, "%s", "END !!!");

merci pour l’aide. :jap: