Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Convert GRAS pid from long int to int; setup a virtualization layer in XBT to choose...
[simgrid.git] / src / xbt / log.c
index bb60ee3..390208d 100644 (file)
 #include "xbt/misc.h"
 #include "xbt/ex.h"
 #include "xbt/sysdep.h"
-#include <xbt/log.h>
+#include "xbt/log.h"
 #include "xbt/dynar.h"
 
+XBT_PUBLIC_DATA(int) (*xbt_pid)();
+
 /** \addtogroup XBT_log
  *
  *  This section describes the API to the log functions used 
@@ -106,7 +108,59 @@ 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).
+
+For now, there is only one format modifyier: the precision field. You can for
+example specify %.4r to get the application age with 4 numbers after the radix.
+
+\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
@@ -204,10 +258,10 @@ First of all, each module should register its own category into the categories
 tree using \ref XBT_LOG_NEW_DEFAULT_SUBCATEGORY.
 
 Then, logging should be done with the DEBUG<n>, VERB<n>, INFO<n>, WARN<n>,
-ERROR<n> or CRITICAL<n> macro families (such as #DEBUG10, #VERB6,
-#INFO8, #WARN6, #ERROR6 and #CRITICAL6). For each group, there is at
-least 6 different macros (like DEBUG0, DEBUG1, DEBUG2, DEBUG3, DEBUG4 and
-DEBUG5), only differing in the number of arguments passed along the format.
+ERROR<n> or CRITICAL<n> macro families (such as #DEBUG10, #VERB10,
+#INFO10, #WARN10, #ERROR10 and #CRITICAL10). For each group, there is at
+least 11 different macros (like DEBUG0, DEBUG1, DEBUG2, DEBUG3, DEBUG4 and
+DEBUG5, DEBUG6, DEBUG7, DEBUG8, DEBUG9, DEBUG10), only differing in the number of arguments passed along the format.
 This is because we want SimGrid itself to keep compilable on ancient
 compiler not supporting variable number of arguments to macros. But we
 should provide a macro simpler to use for the users not interested in SP3
@@ -219,8 +273,8 @@ if you compile with -Wall, the folliwing code will issue a warning:
 
 If you want to specify the category to log onto (for example because you
 have more than one category per file, add a C before the name of the log
-producing macro (ie, use #CDEBUG10, #CVERB6, #CINFO8, #CWARN6, #CERROR6 and
-#CCRITICAL6 and friends), and pass the category name as first argument.
+producing macro (ie, use #CDEBUG10, #CVERB10, #CINFO10, #CWARN10, #CERROR10 and
+#CCRITICAL10 and friends), and pass the category name as first argument.
   
 The TRACE priority is not used the same way than the other. You should use
 the #XBT_IN, XBT_IN<n> (up to #XBT_IN5), #XBT_OUT and #XBT_HERE macros
@@ -239,7 +293,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 &gt;= INFO. * /
        CWARN2(VSS, "Low fuel level.");
@@ -270,13 +324,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 +377,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
@@ -337,23 +392,33 @@ This is on our TODO list for quite a while now, but your help would be
 welcome here, too.
 
 
-*/
+*//*'*/
 
+\f
+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);
   }
 }
+static void _xbt_log_cat_apply_set(xbt_log_category_t category,
+                                  xbt_log_setting_t setting);
 
 const char *xbt_log_priority_names[8] = {
   "NONE",
@@ -366,7 +431,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,53 +443,98 @@ 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.",
+                           (int)(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;
 }
 
 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) {
-       
-      appender->do_append(appender, ev, fmt);
+      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->willLogToParent)
+    if (!cat->additivity)
       break;
 
     cat = cat->parent;
@@ -432,12 +542,70 @@ void _xbt_log_event_log( xbt_log_event_t ev, const char *fmt, ...) {
   va_end(ev->ap);
 }
 
+static void _xbt_log_cat_apply_set(xbt_log_category_t category,
+                                  xbt_log_setting_t setting) { 
+
+  s_xbt_log_event_t _log_ev;
+
+  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);
+    }
+  }
+
+  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 (setting->additivity != -1) {
+    xbt_log_additivity_set(category,setting->additivity);
+    
+    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"));
+    }
+  }
+}
 /*
  * 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) {
+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;
@@ -446,13 +614,11 @@ int _xbt_log_cat_init(e_xbt_log_priority_t priority,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;
+    category->layout = xbt_log_default_layout;
   } else {
 
-#if (defined(_WIN32) && !defined(DLL_STATIC))
-    if(!category->parent){
+    if (!category->parent)
       category->parent = &_XBT_LOGV(XBT_LOG_ROOT_CAT);
-    }
-#endif
     
     xbt_log_parent_set(category, category->parent);
   }
@@ -472,22 +638,9 @@ int _xbt_log_cat_init(e_xbt_log_priority_t priority,xbt_log_category_t category)
       
       found = 1;
       
-      xbt_log_threshold_set(category, setting->thresh);
-      xbt_dynar_cursor_rm(xbt_log_settings,&cursor);
-
+      _xbt_log_cat_apply_set(category,setting);
 
-      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_dynar_cursor_rm(xbt_log_settings,&cursor);
     }
   }
   
@@ -502,7 +655,7 @@ int _xbt_log_cat_init(e_xbt_log_priority_t priority,xbt_log_category_t category)
     _xbt_log_event_log(&_log_ev,
                       "Category '%s': inherited threshold = %s (=%d)",
                       category->name,
-                      xbt_log_priority_names[category->threshold], category->threshold);
+           xbt_log_priority_names[category->threshold], category->threshold);
   }
     
   return priority >= category->threshold;
@@ -537,8 +690,8 @@ void xbt_log_parent_set(xbt_log_category_t cat,xbt_log_category_t parent)
        
        if (parent->threshold == xbt_log_priority_uninitialized){
                
-         _xbt_log_cat_init(xbt_log_priority_uninitialized/* ignored*/,
-                           parent);
+         _xbt_log_cat_init(parent,
+                           xbt_log_priority_uninitialized/* ignored*/);
        }
        
        cat->threshold = parent->threshold;
@@ -549,7 +702,6 @@ void xbt_log_parent_set(xbt_log_category_t cat,xbt_log_category_t parent)
 
 static void _set_inherited_thresholds(xbt_log_category_t cat) {
        
-       
   xbt_log_category_t child = cat->firstChild;
   
   for( ; child != NULL; child = child->nextSibling) {
@@ -574,29 +726,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;
@@ -617,34 +772,55 @@ static void _xbt_log_parse_setting(const char*        control_string,
     if (i<xbt_log_priority_infinite) {
       set->thresh= (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) {
+
+  for(child=cat->firstChild ; child != NULL; child = child->nextSibling) 
     return _xbt_log_cat_searchsub(child,name);
-  }
   
-  THROW0(not_found_error,0,"No such category");
+  THROW1(not_found_error,0,"No such category: %s", name);
 }
 
 /**
@@ -653,54 +829,54 @@ static xbt_log_category_t _xbt_log_cat_searchsub(xbt_log_category_t cat,char *na
  *
  * 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);
+                                    _free_setting);
 
-  set = xbt_new(s_xbt_log_setting_t,1);
-  cs=xbt_strdup(control_string);
+  /* split the string, and remove empty entries */
+  set_strings=xbt_str_split_quoted(control_string);
 
-  xbt_str_strip_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);
@@ -710,29 +886,49 @@ 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);
+      _xbt_log_cat_apply_set(cat,set);
+      _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 && cat != &_XBT_LOGV(root)) {
+    /* better leak the default layout than check every categories to 
+       change it */
+    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;
 }