X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/2539fff313cbd67c45b8490f7961e45e358d9ba2..90f57033e73fcc8191ed4ee325c9b7593eb699e6:/src/xbt/log.c diff --git a/src/xbt/log.c b/src/xbt/log.c index 595576add4..b7ec9022e7 100644 --- a/src/xbt/log.c +++ b/src/xbt/log.c @@ -2,11 +2,10 @@ /* log - a generic logging facility in the spirit of log4j */ -/* Authors: Martin Quinson */ -/* Copyright (C) 2003, 2004 Martin Quinson. */ +/* Copyright (c) 2003, 2004 Martin Quinson. All rights reserved. */ /* This program is free software; you can redistribute it and/or modify it - under the terms of the license (GNU LGPL) which comes with this package. */ + * under the terms of the license (GNU LGPL) which comes with this package. */ #include #include @@ -19,6 +18,301 @@ #include "xbt/error.h" #include "xbt/dynar.h" + +/** \defgroup XBT_log Logging support. + * \brief A generic logging facility in the spirit of log4j + * + * This section describes the API to the log functions used + * everywhere in this project. + +

Overview

+ +This is an adaptation of the log4c project, which is dead upstream, and +which I was given the permission to fork under the LGPL licence by the +authors. log4c itself was loosely based on the Apache project's Log4J, +Log4CC, etc. project. Because C is not object oriented, a lot had to change. + +There is 3 main concepts: category, priority and appender. These three +concepts work together to enable developers to log messages according to +message type and priority, and to control at runtime how these messages are +formatted and where they are reported. + +

Category hierarchy

+ +The first and foremost advantage of any logging API over plain printf() +resides in its ability to disable certain log statements while allowing +others to print unhindered. This capability assumes that the logging space, +that is, the space of all possible logging statements, is categorized +according to some developer-chosen criteria. + +This observation led to choosing category as the central concept of the +system. Every category is declared by providing a name and an optional +parent. If no parent is explicitly named, the root category, LOG_ROOT_CAT is +the category's parent. + +A category is created by a macro call at the top level of a file. A +category can be created with any one of the following macros: + + - \ref XBT_LOG_NEW_CATEGORY(MyCat); Create a new root + - \ref XBT_LOG_NEW_SUBCATEGORY(MyCat, ParentCat); + Create a new category being child of the category ParentCat + - \ref XBT_LOG_NEW_DEFAULT_CATEGORY(MyCat); + Like XBT_LOG_NEW_CATEGORY, but the new category is the default one + in this file + - \ref XBT_LOG_NEW_DEFAULT_SUBCATEGORY(MyCat, ParentCat); + Like XBT_LOG_NEW_SUBCATEGORY, but the new category is the default one + in this file + +The parent cat can be defined in the same file or in another file (in +which case you want to use the \ref XBT_LOG_EXTERNAL_CATEGORY macro to make +it visible in the current file), but each category may have only one +definition. + +Typically, there will be a Category for each module and sub-module, so you +can independently control logging for each module. + +

Priority

+ +A category may be assigned a threshold priorty. The set of priorites are +defined by the \ref e_xbt_log_priority_t enum. All logging request under +this priority will be discarded. + +If a given category is not assigned a threshold priority, then it inherits +one from its closest ancestor with an assigned threshold. To ensure that all +categories can eventually inherit a threshold, the root category always has +an assigned threshold priority. + +Logging requests are made by invoking a logging macro on a category. All of +the macros have a printf-style format string followed by arguments. If you +compile with the -Wall option, gcc will warn you for unmatched arguments, ie +when you pass a pointer to a string where an integer was specified by the +format. This is usualy a good idea. + +Because most C compilers do not support vararg macros, there is a version of +the macro for any number of arguments from 0 to 6. The macro name ends with +the total number of arguments. + +Here is an example of the most basic type of macro. This is a logging +request with priority warning. + +CLOG5(MyCat, gras_log_priority_warning, "Values are: %d and '%s'", 5, +"oops"); + +A logging request is said to be enabled if its priority is higher than or +equal to the threshold priority of its category. Otherwise, the request is +said to be disabled. A category without an assigned priority will inherit +one from the hierarchy. + +It is possible to use any non-negative integer as a priority. If, as in the +example, one of the standard priorites is used, then there is a convenience +macro that is typically used instead. For example, the above example is +equivalent to the shorter: + +CWARN4(MyCat, "Values are: %d and '%s'", 5, "oops"); + +

Default category

+ +If \ref XBT_LOG_NEW_DEFAULT_SUBCATEGORY(MyCat, Parent) or +\ref XBT_LOG_NEW_DEFAULT_CATEGORY(MyCat) is used to create the +category, then the even shorter form can be used: + +WARN3("Values are: %d and '%s'", 5, "oops"); + +Only one default category can be created per file, though multiple +non-defaults can be created and used. + +

Example

+ +Here is a more complete example: + +\verbatim +#include "xbt/log.h" + +/ * create a category and a default subcategory * / +XBT_LOG_NEW_CATEGORY(VSS); +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(SA, VSS); + +int main() { + / * Now set the parent's priority. (the string would typcially be a runtime option) * / + xbt_log_control_set("SA.thresh=3"); + + / * This request is enabled, because WARNING >= INFO. * / + CWARN2(VSS, "Low fuel level."); + + / * This request is disabled, because DEBUG < INFO. * / + CDEBUG2(VSS, "Starting search for nearest gas station."); + + / * The default category SA inherits its priority from VSS. Thus, + the following request is enabled because INFO >= INFO. * / + INFO1("Located nearest gas station."); + + / * This request is disabled, because DEBUG < INFO. * / + DEBUG1("Exiting gas station search"); +} +\endverbatim + +

Configuration

+Configuration is typically done during program initialization by invoking +the xbt_log_control_set() method. The control string passed to it typically +comes from the command line. Look at the documentation for that function for +the format of the control string. + +Any SimGrid program can furthermore be configured at run time by passing a +--xbt-log argument on the command line (--gras-log, --msg-log and +--surf-log are synonyms). You can provide several of those arguments to +change the setting of several categories. + +

Performance

+ +Clever design insures efficiency. Except for the first invocation, a +disabled logging request requires an a single comparison of a static +variable to a constant. + +There is also compile time constant, \ref XBT_LOG_STATIC_THRESHOLD, which +causes all logging requests with a lower priority to be optimized to 0 cost +by the compiler. By setting it to gras_log_priority_infinite, all logging +requests are statically disabled and cost nothing. Released executables +might be compiled with +\verbatim-DXBT_LOG_STATIC_THRESHOLD=gras_log_priority_infinite\endverbatim + +Compiling with the \verbatim-DNLOG\endverbatim option disables all logging +requests at compilation time while the \verbatim-DNDEBUG\endverbatim disables +the requests of priority below INFO. + +

Appenders

+ +Each category has an optional appender. An appender is a pointer to a +structure which starts with a pointer to a doAppend() function. DoAppend() +prints a message to a log. + +When a category is passed a message by one of the logging macros, the +category performs the following actions: + + - if the category has an appender, the message is passed to the + appender's doAppend() function, + - if 'willLogToParent' is true for the category, the message is passed + to the category's parent. + +By default, only the root category have an appender, and 'willLogToParent' +is true for any other category. This situation causes all messages to be +logged by the root category's appender. + +The default appender function currently prints to stderr, and no other one +exist, even if more would be needed, like the one able to send the logs to a +remote dedicated server, or other ones offering different output formats. +This is on our TODO list for quite a while now, but your help would be +welcome here. + +

Misc and Caveats

+ + - Do not use any of the macros that start with '_'. + - Log4J has a 'rolling file appender' which you can select with a run-time + option and specify the max file size. This would be a nice default for + non-kernel applications. + - Careful, category names are global variables. + +*/ + +/* +FAIRE DES ZOLIS LOGS +-------------------- +Dans gras, tu ne te contente pas d'écrire des choses à l'écran, mais tu +écris sur un sujet particulier (notion de canal) des choses d'une gravité +particulière. Il y a 7 niveaux de gravité. + trace: tracer les entrées dans une fonction, retour de fonction + (famille de macros XBT_IN/XBT_OUT) + debug: pour t'aider à mettre au point le module, potentiellement tres bavard + verbose: quelques infos succintes sur les internals du module + info: niveau normal, ton de la conversation + warning: problème potentiel, mais auquel on a su faire face + error: problème qui t'as empêché de faire ton job + critical: juste avant de mourir + +Quand on compile avec -DNDEBUG (par défaut dans le paquet Debian), tout ce +qui est '>= verbose' est supprimé au moment de la compilation. Retiré du +binaire, killé. + +Ensuite, tu écris dans un canal particulier. Tous les canaux sont rangés en +arbre. Il faudrait faire un ptit script qui fouille les sources à la +recherche des macros XBT_LOG_NEW_* utilisées pour créer des canaux. Le +dernier argument de ces macros est ignoré dans le source. Il est destiné à +être la documentation de la chose en une ligne. En gros, ca fait: +root + +--xbt + | +--config + | +--dict + | | +--dict_cursor + | | +--dict_elm + | | ... + | +--dynar + | +--set + | +--log + | +--module + +--gras + +--datadesc + | +--ddt_cbps + | +--ddt_convert + | +--ddt_exchange + | +--ddt_parse + | +--lexer + +--msg + +--transport + +--raw_trp (Je devrais tuer ce module, un jour) + +--trp_buf + +--trp_sg + +--trp_file + +--trp_tcp + +Et ensuite les utilisateurs peuvent choisir le niveau de gravité qui les +interresse sur tel ou tel sujet. + +Toute la mécanique de logging repose sur des variables statiques dont le nom +dépend du nom du canal. + => attention aux conflits de nom de canal + => il faut une macro XBT_LOG dans chaque fichier où tu fais des logs. + +XBT_LOG_NEW_CATEGORY: nouveau canal sous "root". Rare, donc. +XBT_LOG_NEW_SUBCATEGORY: nouveau canal dont on précise le père. +XBT_LOG_DEFAULT_CATEGORY: indique quel est le canal par défaut dans ce fichier +XBT_LOG_NEW_DEFAULT_CATEGORY: Crèe un canal et l'utilise par défaut +XBT_LOG_NEW_DEFAULT_SUBCATEGORY: devine +XBT_LOG_EXTERNAL_CATEGORY: quand tu veux utiliser par défaut un canal créé + dans un autre fichier. + +Une fois que ton canal est créé, tu l'utilise avec les macros LOG, DEBUG, +VERB, WARN, ERROR et CRITICAL. Il faut que tu donne le nombre d'arguments +après le nom de macro. Exemple: LOG2("My name is %s %s","Martin","Quinson") +Si tu veux préciser explicitement le canal où écrire, ajoute un C devant le +nom de la macro. Exemple: CCRITICAL0(module, "Cannot initialize GRAS") + +Toutes ces macros (enfin, ce en quoi elles se réécrivent) vérifient leurs +arguments comme printf le fait lorsqu'on compile avec gcc. +LOG1("name: %d","toto"); donne un warning, et donc une erreur en mode +mainteneur. + +Enfin, tu peux tester si un canal est ouvert à une priorité donnée (pour +préparer plus de débug, par exemple. Dans le parseur, je fais du pretty +printing sur ce qu'il faut parser dans ce cas). +XBT_LOG_ISENABLED(catName, priority) Le second argument doit être une valeur +de e_xbt_log_priority_t (log.h). Par exemple: xbt_log_priority_verbose + +Voila sur comment mettre des logs dans ton code. N'hesite pas à faire pleins +de canaux différents pour des aspects différents de ton code. En +particulier, dans les dict, j'ai un canal pour l'ajout, le retrait, le +netoyage du code après suppression et ainsi de suite. De cette façon, je +peux choisir qui m'interresse. + + +Pour utiliser les logs, tu déjà faire, non ? Tu colle sur la ligne de +commande un ou plusieurs arguments de la forme + --gras-log=" [+]" (ou sans " si t'as pas d'espace) +chaque réglage étant de la forme: + .thres= +Les différents réglages sont lus de gauche à droite. +"root.thres=debug root.thres=critical" ferme tout, normalement. + +*/ + typedef struct { char *catname; e_xbt_log_priority_t thresh; @@ -50,10 +344,45 @@ s_xbt_log_category_t _XBT_LOGV(XBT_LOG_ROOT_CAT) = { NULL, 0 }; -XBT_LOG_NEW_SUBCATEGORY(gras,XBT_LOG_ROOT_CAT,"All GRAS categories"); -XBT_LOG_NEW_SUBCATEGORY(xbt,XBT_LOG_ROOT_CAT,"All XBT categories (gras toolbox)"); +XBT_LOG_NEW_SUBCATEGORY(xbt,XBT_LOG_ROOT_CAT,"All XBT categories (simgrid toolbox)"); +XBT_LOG_NEW_SUBCATEGORY(surf,XBT_LOG_ROOT_CAT,"All SURF categories"); XBT_LOG_NEW_DEFAULT_SUBCATEGORY(log,xbt,"Loggings from the logging mecanism itself"); +void xbt_log_init(int *argc,char **argv, const char *defaultlog) { + int i,j; + char *opt; + int found=0; + + /* Set logs and init log submodule */ + for (i=1; i<*argc; i++) { + if (!strncmp(argv[i],"--gras-log=",strlen("--gras-log=")) || + !strncmp(argv[i],"--surf-log=",strlen("--surf-log=")) || + !strncmp(argv[i],"--msg-log=",strlen("--msg-log=")) || + !strncmp(argv[i],"--xbt-log=",strlen("--xbt-log="))) { + found = 1; + opt=strchr(argv[i],'='); + opt++; + xbt_log_control_set(opt); + DEBUG1("Did apply '%s' as log setting",opt); + /*remove this from argv*/ + for (j=i+1; j<*argc; j++) { + argv[j-1] = argv[j]; + } + argv[j-1] = NULL; + (*argc)--; + i--; /* compensate effect of next loop incrementation */ + } + } + if (!found && defaultlog) { + xbt_log_control_set(defaultlog); + } +} + +void xbt_log_exit(void) { + VERB0("Exiting log"); + xbt_dynar_free(&xbt_log_settings); + VERB0("Exited log"); +} static void _apply_control(xbt_log_category_t cat) { int cursor; @@ -293,8 +622,8 @@ static void _cleanup_double_spaces(char *s) { } /** - * xbt_log_control_set: - * @cs: What to parse + * \ingroup XBT_log + * \param control_string What to parse * * Typically passed a command-line argument. The string has the syntax: * @@ -306,7 +635,7 @@ static void _cleanup_double_spaces(char *s) { * thresh value is an integer priority level. Sets the category's * threshold priority. * - * @warning + * \warning * This routine may only be called once and that must be before any other * logging command! Typically, this is done from main(). */ @@ -363,8 +692,3 @@ void xbt_log_appender_set(xbt_log_category_t cat, xbt_log_appender_t app) { cat->appender = app; } -void xbt_log_exit(void) { - VERB0("Exiting log"); - xbt_dynar_free(&xbt_log_settings); - VERB0("Exited log"); -}