X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/963c8f3d1cd6f63552673bdbc62252b90e4e6ffa..12442080c860b7affd1b246f12895bda4f304330:/src/xbt/log.c diff --git a/src/xbt/log.c b/src/xbt/log.c index 123ad9dd84..baed936a06 100644 --- a/src/xbt/log.c +++ b/src/xbt/log.c @@ -106,7 +106,56 @@ relevant to debugging information, not to critical error messages. One day, for sure ;) -\subsection log_hist 1.4 History of this module +\subsection log_lay 1.4 Message layouts + +The message layouts are the elements in charge of choosing how each message +will look like. Their result is a string which is then passed to the appender +attached to the category to be displayed. + +For now, there is two layouts: The simple one, which is good for most cases, +and another one allowing users to specify the format they want. + +Here are the existing format directives: + + - %%: the % char + - %n: platform-dependant line separator (LOG4J compliant) + - %e: plain old space (SimGrid extension) + + - %m: user-provided message + + - %c: Category name (LOG4J compliant) + - %p: Priority name (LOG4J compliant) + + - %h: Hostname (SimGrid extension) + - %t: Process name (LOG4J compliant -- thread name in LOG4J) + - %I: Process PID (SimGrid extension) + + - %F: file name where the log event was raised (LOG4J compliant) + - %l: location where the log event was raised (LOG4J compliant, like '%F:%L') + - %L: line number where the log event was raised (LOG4J compliant) + - %M: function name (LOG4J compliant -- called method name here of course). + Defined only when using gcc because there is no __FUNCTION__ elsewhere. + + - %b: full backtrace (Called %throwable in LOG4J). + Defined only when using the GNU libc because backtrace() is not defined + elsewhere. + - %B: short backtrace (only the first line of the %b). + Called %throwable{short} in LOG4J, defined where %b is. + + - %d: date (UNIX epoch) + - %r: application age (time elapsed since the beginning of the application) + + +If you want to mimick the simple layout with the format one, you would use this +format: '[%h:%i:(%I) %r] %l: [%c/%p] %m%n'. This is not completely correct +because the simple layout do not display the message location for messages at +priority INFO (thus, the fmt is '[%h:%i:(%I) %r] %l: [%c/%p] %m%n' in this +case). Moreover, if there is no process name (ie, messages comming from the +library itself, or test programs doing strange things) do not display the +process identity (thus, fmt is '[%r] %l: [%c/%p] %m%n' in that case, and '[%r] +[%c/%p] %m%n' if they are at priority INFO). + +\subsection log_hist 1.5 History of this module Historically, this module is an adaptation of the log4c project, which is dead upstream, and which I was given the permission to fork under the LGPL licence @@ -239,7 +288,7 @@ 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"); + xbt_log_control_set("SA.thresh:3"); / * This request is enabled, because WARNING >= INFO. * / CWARN2(VSS, "Low fuel level."); @@ -270,13 +319,13 @@ Any SimGrid program can furthermore be configured at run time by passing a are synonyms provided by aestheticism). You can provide several of those arguments to change the setting of several categories, they will be applied from left to right. So, -\verbatim --xbt-log="root.thres=debug root.thres=critical"\endverbatim +\verbatim --xbt-log="root.thres:debug root.thres:critical"\endverbatim should disable any logging. Note that the quotes on above line are mandatory because there is a space in the argument, so we are protecting ourselves from the shell, not from SimGrid. We could also reach the same effect with this: -\verbatim --xbt-log=root.thres=debug --xbt-log=root.thres=critical\endverbatim +\verbatim --xbt-log=root.thres:debug --xbt-log=root.thres:critical\endverbatim \section log_use_misc 3.2 Misc and Caveats @@ -323,12 +372,13 @@ 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. + - if additivity is true for the category (which is the case by + default, and can be controlled by xbt_log_additivity_set()), 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. +By default, only the root category have an appender, and any other category has +its additivity set to true. This 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 @@ -339,19 +389,27 @@ welcome here, too. */ + +xbt_log_appender_t xbt_log_default_appender = NULL; /* set in log_init */ +xbt_log_layout_t xbt_log_default_layout = NULL; /* set in log_init */ +int _log_usable = 0; typedef struct { char *catname; e_xbt_log_priority_t thresh; + char *fmt; + int additivity; } s_xbt_log_setting_t,*xbt_log_setting_t; static xbt_dynar_t xbt_log_settings=NULL; static void _free_setting(void *s) { - xbt_log_setting_t set=(xbt_log_setting_t)s; + xbt_log_setting_t set=*(xbt_log_setting_t*)s; if (set) { free(set->catname); -/* free(set); FIXME: uncommenting this leads to segfault when more than one chunk is passed as gras-log */ + if (set->fmt) + free(set->fmt); + free(set); } } @@ -366,7 +424,7 @@ const char *xbt_log_priority_names[8] = { "CRITICAL" }; -s_xbt_log_category_t XBT_PUBLIC_DATA _XBT_LOGV(XBT_LOG_ROOT_CAT) = { +XBT_PUBLIC_DATA(s_xbt_log_category_t) _XBT_LOGV(XBT_LOG_ROOT_CAT) = { 0, 0, 0, "root", xbt_log_priority_uninitialized, 0, NULL, 0 @@ -378,170 +436,220 @@ XBT_LOG_NEW_CATEGORY(msg,"All MSG categories"); XBT_LOG_NEW_CATEGORY(simix,"All SIMIX categories"); XBT_LOG_NEW_DEFAULT_SUBCATEGORY(log,xbt,"Loggings from the logging mechanism itself"); +/** @brief Get all logging settings from the command line + * + * xbt_log_control_set() is called on each string we got from cmd line + */ void xbt_log_init(int *argc,char **argv) { int i,j; char *opt; + /* create the default appender and install it in the root category, + which were already created (damnit. Too slow little beetle)*/ + xbt_log_default_appender = xbt_log_appender_file_new(NULL); + xbt_log_default_layout = xbt_log_layout_simple_new(NULL); + _XBT_LOGV(XBT_LOG_ROOT_CAT).appender = xbt_log_default_appender; + _XBT_LOGV(XBT_LOG_ROOT_CAT).layout = xbt_log_default_layout; + _log_usable = 1; + /* 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],"--simix-log=",strlen("--simix-log=")) || - !strncmp(argv[i],"--xbt-log=",strlen("--xbt-log="))){ - - 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 (!strncmp(argv[i],"--log=",strlen("--log=")) || + !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],"--simix-log=",strlen("--simix-log=")) || + !strncmp(argv[i],"--xbt-log=",strlen("--xbt-log="))){ + + if (strncmp(argv[i],"--log=",strlen("--log="))) + WARN2("Option %.*s is deprecated and will disapear in the future. Use --log instead.", + strchr(argv[i],'=')-argv[i],argv[i]); + + 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 */ } } } +static void log_cat_exit(xbt_log_category_t cat) { + xbt_log_category_t child; + + if (cat->appender) { + if (cat->appender->free_) + cat->appender->free_(cat->appender); + free(cat->appender); + } + if (cat->layout) { + if (cat->layout->free_) + cat->layout->free_(cat->layout); + free(cat->layout); + } + + for(child=cat->firstChild ; child != NULL; child = child->nextSibling) + log_cat_exit(child); +} + void xbt_log_exit(void) { VERB0("Exiting log"); xbt_dynar_free(&xbt_log_settings); - VERB0("Exited log"); + log_cat_exit(&_XBT_LOGV(XBT_LOG_ROOT_CAT)); + _log_usable = 0; } -static void _apply_control(xbt_log_category_t cat) { +void _xbt_log_event_log( xbt_log_event_t ev, const char *fmt, ...) { + + xbt_log_category_t cat = ev->cat; + if (!_log_usable) { + fprintf(stderr,"XXXXXXXXXXXXXXXXXXX\nXXX Warning, logs not usable here. Either before xbt_init() or after xbt_exit().\nXXXXXXXXXXXXXXXXXXX\n"); + va_start(ev->ap, fmt); + vfprintf(stderr,fmt,ev->ap); + va_end(ev->ap); + xbt_backtrace_display(); + return; + } + + va_start(ev->ap, fmt); + while(1) { + xbt_log_appender_t appender = cat->appender; + if (appender != NULL) { + xbt_assert1(cat->layout,"No valid layout for the appender of category %s",cat->name); + char *str= cat->layout->do_layout(cat->layout, ev, fmt); + appender->do_append(appender, str); + } + if (!cat->additivity) + break; + + cat = cat->parent; + } + va_end(ev->ap); +} + +/* + * This gets called the first time a category is referenced and performs the + * initialization. + * Also resets threshold to inherited! + */ +int _xbt_log_cat_init(xbt_log_category_t category, + e_xbt_log_priority_t priority) { int cursor; xbt_log_setting_t setting=NULL; int found = 0; s_xbt_log_event_t _log_ev; - - - + + if(category == &_XBT_LOGV(XBT_LOG_ROOT_CAT)){ + category->threshold = xbt_log_priority_info;/* xbt_log_priority_debug*/; + category->appender = xbt_log_default_appender; + category->layout = xbt_log_default_layout; + } else { + + if (!category->parent) + category->parent = &_XBT_LOGV(XBT_LOG_ROOT_CAT); + + xbt_log_parent_set(category, category->parent); + } + + /* Apply the control */ if (!xbt_log_settings) - return; + return priority >= category->threshold; + + xbt_assert0(category,"NULL category"); + xbt_assert(category->name); - xbt_assert0(cat,"NULL category"); - xbt_assert(cat->name); - xbt_dynar_foreach(xbt_log_settings,cursor,setting) { xbt_assert0(setting,"Damnit, NULL cat in the list"); xbt_assert1(setting->catname,"NULL setting(=%p)->catname",(void*)setting); - - if (!strcmp(setting->catname,cat->name)) { - + if (!strcmp(setting->catname,category->name)) { + found = 1; + + if (setting->thresh != xbt_log_priority_uninitialized) { + xbt_log_threshold_set(category, setting->thresh); + + if (category->threshold <= xbt_log_priority_debug) { + _log_ev.cat = category; + _log_ev.priority = xbt_log_priority_debug; + _log_ev.fileName = __FILE__ ; + _log_ev.functionName = _XBT_FUNCTION ; + _log_ev.lineNum = __LINE__ ; + + _xbt_log_event_log(&_log_ev, + "Apply settings for category '%s': set threshold to %s (=%d)", + category->name, + xbt_log_priority_names[category->threshold], + category->threshold); + } + } - xbt_log_threshold_set(cat, setting->thresh); - xbt_dynar_cursor_rm(xbt_log_settings,&cursor); + if (setting->fmt) { + xbt_log_layout_set(category,xbt_log_layout_format_new(setting->fmt)); + if (category->threshold <= xbt_log_priority_debug) { + _log_ev.cat = category; + _log_ev.priority = xbt_log_priority_debug; + _log_ev.fileName = __FILE__ ; + _log_ev.functionName = _XBT_FUNCTION ; + _log_ev.lineNum = __LINE__ ; + + _xbt_log_event_log(&_log_ev, + "Apply settings for category '%s': set format to %s", + category->name, + setting->fmt); + } + } - if (cat->threshold <= xbt_log_priority_debug) { - _log_ev.cat = cat; - _log_ev.priority = xbt_log_priority_debug; - _log_ev.fileName = __FILE__ ; - _log_ev.functionName = _XBT_FUNCTION ; - _log_ev.lineNum = __LINE__ ; + if (setting->additivity != -1) { + xbt_log_additivity_set(category,setting->additivity); - _xbt_log_event_log(&_log_ev, - "Apply settings for category '%s': set threshold to %s (=%d)", - cat->name, - xbt_log_priority_names[cat->threshold], cat->threshold); + if (category->threshold <= xbt_log_priority_debug) { + _log_ev.cat = category; + _log_ev.priority = xbt_log_priority_debug; + _log_ev.fileName = __FILE__ ; + _log_ev.functionName = _XBT_FUNCTION ; + _log_ev.lineNum = __LINE__ ; + + _xbt_log_event_log(&_log_ev, + "Apply settings for category '%s': set additivity to %s", + category->name, + (setting->additivity?"on":"off")); + } } + + xbt_dynar_cursor_rm(xbt_log_settings,&cursor); } - } - if (!found && cat->threshold <= xbt_log_priority_verbose) { - - _log_ev.cat = cat; + if (!found && category->threshold <= xbt_log_priority_verbose) { + + _log_ev.cat = category; _log_ev.priority = xbt_log_priority_verbose; _log_ev.fileName = __FILE__ ; _log_ev.functionName = _XBT_FUNCTION ; _log_ev.lineNum = __LINE__ ; - + _xbt_log_event_log(&_log_ev, - "Category '%s': inherited threshold = %s (=%d)", - cat->name, - xbt_log_priority_names[cat->threshold], cat->threshold); + "Category '%s': inherited threshold = %s (=%d)", + category->name, + xbt_log_priority_names[category->threshold], category->threshold); } - - - -} - -void _xbt_log_event_log( xbt_log_event_t ev, const char *fmt, ...) { - - - xbt_log_category_t cat = ev->cat; - - - - - va_start(ev->ap, fmt); - while(1) { - xbt_log_appender_t appender = cat->appender; - if (appender != NULL) { - - appender->do_append(appender, ev, fmt); - } - if (!cat->willLogToParent) - break; - - cat = cat->parent; - } - va_end(ev->ap); -} - -static void _cat_init(xbt_log_category_t category) -{ - - - if(category == &_XBT_LOGV(XBT_LOG_ROOT_CAT)){ - category->threshold = xbt_log_priority_info;/* xbt_log_priority_debug*/; - category->appender = xbt_log_default_appender; - } - else - { - - #if (defined(_WIN32) && !defined(DLL_STATIC)) - if(!category->parent){ - category->parent = &_XBT_LOGV(XBT_LOG_ROOT_CAT); - } - #endif - - xbt_log_parent_set(category, category->parent); - } - - _apply_control(category); - - -} - -/* - * This gets called the first time a category is referenced and performs the - * initialization. - * Also resets threshold to inherited! - */ -int _xbt_log_cat_init(e_xbt_log_priority_t priority,xbt_log_category_t category) -{ - _cat_init(category); - - - - - return priority >= category->threshold; + return priority >= category->threshold; } void xbt_log_parent_set(xbt_log_category_t cat,xbt_log_category_t parent) { - xbt_assert0(cat,"NULL category to be given a parent"); xbt_assert1(parent,"The parent category of %s is NULL",cat->name); @@ -568,16 +676,15 @@ void xbt_log_parent_set(xbt_log_category_t cat,xbt_log_category_t parent) if (parent->threshold == xbt_log_priority_uninitialized){ - _cat_init(parent); + _xbt_log_cat_init(parent, + xbt_log_priority_uninitialized/* ignored*/); } cat->threshold = parent->threshold; cat->isThreshInherited = 1; - - -} /* log_setParent */ +} static void _set_inherited_thresholds(xbt_log_category_t cat) { @@ -606,29 +713,32 @@ void xbt_log_threshold_set(xbt_log_category_t cat, } -static void _xbt_log_parse_setting(const char* control_string, - xbt_log_setting_t set) { +static xbt_log_setting_t _xbt_log_parse_setting(const char* control_string) { + + xbt_log_setting_t set = xbt_new(s_xbt_log_setting_t,1); const char *name, *dot, *eq; - - set->catname=NULL; + set->thresh = xbt_log_priority_uninitialized; + set->fmt = NULL; + set->additivity = -1; + if (!*control_string) - return; + return set; DEBUG1("Parse log setting '%s'",control_string); control_string += strspn(control_string, " "); name = control_string; control_string += strcspn(control_string, ".= "); dot = control_string; - control_string += strcspn(control_string, "= "); + control_string += strcspn(control_string, ":= "); eq = control_string; control_string += strcspn(control_string, " "); - xbt_assert1(*dot == '.' && *eq == '=', + xbt_assert1(*dot == '.' && (*eq == '=' || *eq == ':'), "Invalid control string '%s'",control_string); - if (!strncmp(dot + 1, "thresh", min((size_t)(eq - dot - 1),strlen("thresh")))) { + if (!strncmp(dot + 1, "thresh", (size_t)(eq - dot - 1))) { int i; char *neweq=xbt_strdup(eq+1); char *p=neweq-1; @@ -649,66 +759,55 @@ static void _xbt_log_parse_setting(const char* control_string, if (ithresh= (e_xbt_log_priority_t) i; } else { - xbt_assert1(FALSE,"Unknown priority name: %s",eq+1); + THROW1(arg_error,0, + "Unknown priority name: %s (must be one of: trace,debug,verbose,info,warning,error,critical)",eq+1); } free(neweq); + } else if ( !strncmp(dot + 1, "add", (size_t)(eq - dot - 1)) || + !strncmp(dot + 1, "additivity", (size_t)(eq - dot - 1)) ) { + + char *neweq=xbt_strdup(eq+1); + char *p=neweq-1; + + while (*(++p) != '\0') { + if (*p >= 'a' && *p <= 'z') { + *p-='a'-'A'; + } + } + if ( !strcmp(neweq,"ON") || + !strcmp(neweq,"YES") || + !strcmp(neweq,"1") ) { + set->additivity = 1; + } else { + set->additivity = 0; + } + free(neweq); + } else if (!strncmp(dot + 1, "fmt", (size_t)(eq - dot - 1))) { + set->fmt = xbt_strdup(eq+1); } else { char buff[512]; - snprintf(buff,min(512,eq - dot - 1),"%s",dot+1); - xbt_assert1(FALSE,"Unknown setting of the log category: %s",buff); + snprintf(buff,min(512,eq - dot),"%s",dot+1); + THROW1(arg_error,0,"Unknown setting of the log category: '%s'",buff); } set->catname=(char*)xbt_malloc(dot - name+1); - strncpy(set->catname,name,dot-name); + memcpy(set->catname,name,dot-name); set->catname[dot-name]='\0'; /* Just in case */ DEBUG1("This is for cat '%s'", set->catname); + return set; } static xbt_log_category_t _xbt_log_cat_searchsub(xbt_log_category_t cat,char *name) { xbt_log_category_t child; - - if (!strcmp(cat->name,name)) { + if (!strcmp(cat->name,name)) return cat; - } - for(child=cat->firstChild ; child != NULL; child = child->nextSibling) { - return _xbt_log_cat_searchsub(child,name); - } - - THROW0(not_found_error,0,"No such category"); -} -static void _cleanup_double_spaces(char *s) { - char *p = s; - int e = 0; - - while (1) { - if (!*p) - goto end; - - if (!isspace(*p)) - break; - - p++; - } - - e = 1; + for(child=cat->firstChild ; child != NULL; child = child->nextSibling) + return _xbt_log_cat_searchsub(child,name); - do { - if (e) - *s++ = *p; - - if (!*++p) - goto end; - - if (e ^ !isspace(*p)) - if ((e = !e)) - *s++ = ' '; - } while (1); - - end: - *s = '\0'; + THROW1(not_found_error,0,"No such category: %s", name); } /** @@ -717,54 +816,62 @@ static void _cleanup_double_spaces(char *s) { * * Typically passed a command-line argument. The string has the syntax: * - * ( [category] "." [keyword] "=" value (" ")... )... + * ( [category] "." [keyword] ":" value (" ")... )... * - * where [category] is one the category names (see \ref XBT_log_cats for a complete list) + * where [category] is one the category names (see \ref XBT_log_cats for + * a complete list of the ones defined in the SimGrid library) * and keyword is one of the following: * * - thres: category's threshold priority. Possible values: * TRACE,DEBUG,VERBOSE,INFO,WARNING,ERROR,CRITICAL - * - * - * \warning - * This routine may only be called once and that must be before any other - * logging command! Typically, this is done from main(). - * \todo the previous warning seems a bit old and need double checking + * - add or additivity: whether the logging actions must be passed to + * the parent category. + * Possible values: 0, 1, no, yes, on, off. + * Default value: yes. + * - fmt: the format to use. See \ref log_lay for more information. + * */ void xbt_log_control_set(const char* control_string) { xbt_log_setting_t set; - char *cs; - char *p; - int done = 0; - - - - DEBUG1("Parse log settings '%s'",control_string); - if (control_string == NULL) + + /* To split the string in commands, and the cursors */ + xbt_dynar_t set_strings; + char *str; + int cpt; + + if (!control_string) return; + DEBUG1("Parse log settings '%s'",control_string); + + /* some initialization if this is the first time that this get called */ if (xbt_log_settings == NULL) xbt_log_settings = xbt_dynar_new(sizeof(xbt_log_setting_t), - _free_setting); - - set = xbt_new(s_xbt_log_setting_t,1); - cs=xbt_strdup(control_string); + _free_setting); + + /* split the string, and remove empty entries */ + set_strings=xbt_str_split_quoted(control_string); +#ifdef FIXME + xbt_dynar_foreach(set_strings,cpt,str) { + xbt_str_trim(str,NULL); + if (str[0]=='\0') { + xbt_dynar_cursor_rm(set_strings,&cpt); + } + } +#endif - _cleanup_double_spaces(cs); + if (xbt_dynar_length(set_strings) == 0) { /* vicious user! */ + xbt_dynar_free(&set_strings); + return; + } - while (!done) { + /* Parse each entry and either use it right now (if the category was already + created), or store it for further use */ + xbt_dynar_foreach(set_strings,cpt,str) { xbt_log_category_t cat=NULL; int found=0; xbt_ex_t e; - p=strrchr(cs,' '); - if (p) { - *p='\0'; - p++; - } else { - p=cs; - done = 1; - } - _xbt_log_parse_setting(p,set); + set = _xbt_log_parse_setting(str); TRY { cat = _xbt_log_cat_searchsub(&_XBT_LOGV(root),set->catname); @@ -774,29 +881,47 @@ void xbt_log_control_set(const char* control_string) { RETHROW; xbt_ex_free(e); found = 0; - - DEBUG0("Store for further application"); - DEBUG1("push %p to the settings",(void*)set); - xbt_dynar_push(xbt_log_settings,&set); - /* malloc in advance the next slot */ - set = xbt_new(s_xbt_log_setting_t,1); } if (found) { DEBUG0("Apply directly"); - free(set->catname); xbt_log_threshold_set(cat,set->thresh); + _free_setting((void*)&set); + } else { + + DEBUG0("Store for further application"); + DEBUG1("push %p to the settings",(void*)set); + xbt_dynar_push(xbt_log_settings,&set); } } - free(set); - free(cs); - - + xbt_dynar_free(&set_strings); } void xbt_log_appender_set(xbt_log_category_t cat, xbt_log_appender_t app) { - + if (cat->appender) { + if (cat->appender->free_) + cat->appender->free_(cat->appender); + free(cat->appender); + } cat->appender = app; - +} +void xbt_log_layout_set(xbt_log_category_t cat, xbt_log_layout_t lay) { + if (!cat->appender) { + VERB1("No appender to category %s. Setting the file appender as default", + cat->name); + xbt_log_appender_set(cat,xbt_log_appender_file_new(NULL)); + } + if (cat->layout) { + if (cat->layout->free_) { + cat->layout->free_(cat->layout); + free(cat->layout); + } + } + cat->layout = lay; + xbt_log_additivity_set(cat,0); +} + +void xbt_log_additivity_set(xbt_log_category_t cat, int additivity) { + cat->additivity = additivity; }