Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
cleanup + more asserting for robustness
[simgrid.git] / src / xbt / log.c
index e80332a..55fa192 100644 (file)
@@ -12,7 +12,7 @@
 #include <ctype.h>
 #include <stdio.h> /* snprintf */
 #include <stdlib.h> /* snprintf */
 #include <ctype.h>
 #include <stdio.h> /* snprintf */
 #include <stdlib.h> /* snprintf */
-#include "gras_config.h" /* to get a working stdarg.h */
+
 #include "portable.h" /* to get a working stdarg.h */
 
 #include "xbt_modinter.h"
 #include "portable.h" /* to get a working stdarg.h */
 
 #include "xbt_modinter.h"
@@ -20,7 +20,7 @@
 #include "xbt/misc.h"
 #include "xbt/ex.h"
 #include "xbt/sysdep.h"
 #include "xbt/misc.h"
 #include "xbt/ex.h"
 #include "xbt/sysdep.h"
-#include "xbt/log.h"
+#include <xbt/log.h>
 #include "xbt/dynar.h"
 
 /** \addtogroup XBT_log
 #include "xbt/dynar.h"
 
 /** \addtogroup XBT_log
@@ -204,17 +204,28 @@ 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>,
 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. For each group, there is 6 different
-macros (like DEBUG0, DEBUG1, DEBUG2, DEBUG3, DEBUG4 and DEBUG5), 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 machines (FIXME).
-
+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.
+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
+machines (FIXME).
+  
 Under GCC, these macro check there arguments the same way than printf does. So,
 if you compile with -Wall, the folliwing code will issue a warning:
 <code>DEBUG2("Found %s (id %f)", some_string, a_double)</code>
 
 Under GCC, these macro check there arguments the same way than printf does. So,
 if you compile with -Wall, the folliwing code will issue a warning:
 <code>DEBUG2("Found %s (id %f)", some_string, a_double)</code>
 
+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.
+  
+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
+instead.
+
 \section log_API_example 2.5 Example of use
 
 Here is a more complete example:
 \section log_API_example 2.5 Example of use
 
 Here is a more complete example:
@@ -228,7 +239,7 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(SA, VSS);
 
 int main() {
        / * Now set the parent's priority.  (the string would typcially be a runtime option) * /
 
 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.");
 
        / * This request is enabled, because WARNING &gt;= INFO. * /
        CWARN2(VSS, "Low fuel level.");
@@ -259,13 +270,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, 
 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:
 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
 
 
 \section log_use_misc 3.2 Misc and Caveats
 
@@ -312,12 +323,13 @@ category performs the following actions:
 
   - if the category has an appender, the message is passed to the
     appender's doAppend() function,
 
   - 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
 
 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
@@ -328,6 +340,8 @@ welcome here, too.
 
 */
 
 
 */
 
+\f
+xbt_log_appender_t xbt_log_default_appender = NULL; /* set in log_init */
 
 typedef struct {
   char *catname;
 
 typedef struct {
   char *catname;
@@ -335,11 +349,12 @@ typedef struct {
 } s_xbt_log_setting_t,*xbt_log_setting_t;
 
 static xbt_dynar_t xbt_log_settings=NULL;
 } s_xbt_log_setting_t,*xbt_log_setting_t;
 
 static xbt_dynar_t xbt_log_settings=NULL;
+
 static void _free_setting(void *s) {
 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);
   if (set) {
     free(set->catname);
-/*    free(set); FIXME: uncommenting this leads to segfault when more than one chunk is passed as gras-log */
+    free(set);
   }
 }
 
   }
 }
 
@@ -354,7 +369,7 @@ const char *xbt_log_priority_names[8] = {
   "CRITICAL"
 };
 
   "CRITICAL"
 };
 
-s_xbt_log_category_t _XBT_LOGV(XBT_LOG_ROOT_CAT) = {
+s_xbt_log_category_t XBT_PUBLIC_DATA  _XBT_LOGV(XBT_LOG_ROOT_CAT) = {
   0, 0, 0,
   "root", xbt_log_priority_uninitialized, 0,
   NULL, 0
   0, 0, 0,
   "root", xbt_log_priority_uninitialized, 0,
   NULL, 0
@@ -363,90 +378,89 @@ s_xbt_log_category_t _XBT_LOGV(XBT_LOG_ROOT_CAT) = {
 XBT_LOG_NEW_CATEGORY(xbt,"All XBT categories (simgrid toolbox)");
 XBT_LOG_NEW_CATEGORY(surf,"All SURF categories");
 XBT_LOG_NEW_CATEGORY(msg,"All MSG categories");
 XBT_LOG_NEW_CATEGORY(xbt,"All XBT categories (simgrid toolbox)");
 XBT_LOG_NEW_CATEGORY(surf,"All SURF categories");
 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");
 
 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) {
 void xbt_log_init(int *argc,char **argv) {
-  int i,j;
-  char *opt;
-
-  /* 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="))) {
-      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 */
+       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(xbt_log_layout_simple_new());
+       _XBT_LOGV(XBT_LOG_ROOT_CAT).appender = xbt_log_default_appender;
+
+       /* Set logs and init log submodule */
+       for (i=1; i<*argc; i++){
+               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="))){
+                               
+                 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->layout) {
+      if (cat->appender->layout->free_)
+       cat->appender->layout->free_(cat->appender->layout);
+      free(cat->appender->layout);
     }
     }
+    if (cat->appender->free_)
+      cat->appender->free_(cat->appender);
+    free(cat->appender);
   }
   }
+    
+
+  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);
 }
 
 void xbt_log_exit(void) {
   VERB0("Exiting log");
   xbt_dynar_free(&xbt_log_settings);
+  log_cat_exit(&_XBT_LOGV(XBT_LOG_ROOT_CAT));
   VERB0("Exited log");
 }
 
   VERB0("Exited log");
 }
 
-static void _apply_control(xbt_log_category_t cat) {
-  int cursor;
-  xbt_log_setting_t setting=NULL;
-  int found = 0;
-
-  if (!xbt_log_settings)
-    return;
-
-  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)) {
-      found = 1;
-
-      xbt_log_threshold_set(cat, setting->thresh);
-      xbt_dynar_cursor_rm(xbt_log_settings,&cursor);
-
-      if (cat->threshold <= xbt_log_priority_debug) {
-       s_xbt_log_event_t _log_ev = 
-         {cat,xbt_log_priority_debug,__FILE__,_XBT_FUNCTION,__LINE__};
-       _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 (!found && cat->threshold <= xbt_log_priority_verbose) {
-    s_xbt_log_event_t _log_ev = 
-      {cat,xbt_log_priority_verbose,__FILE__,_XBT_FUNCTION,__LINE__};
-    _xbt_log_event_log(&_log_ev,
-                       "Category '%s': inherited threshold = %s (=%d)",
-                       cat->name,
-                       xbt_log_priority_names[cat->threshold], cat->threshold);
-  }
-
-}
-
 void _xbt_log_event_log( xbt_log_event_t ev, const char *fmt, ...) {
 void _xbt_log_event_log( xbt_log_event_t ev, const char *fmt, ...) {
+  
   xbt_log_category_t cat = ev->cat;
   xbt_log_category_t cat = ev->cat;
+  
   va_start(ev->ap, fmt);
   while(1) {
     xbt_log_appender_t appender = cat->appender;
     if (appender != NULL) {
   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(appender->layout,"No valid layout for the appender of category %s",cat->name);
+      char *str= appender->layout->do_layout(appender->layout,
+                                            ev, fmt);    
+      appender->do_append(appender, str);
     }
     }
-    if (!cat->willLogToParent)
+    if (!cat->additivity)
       break;
 
     cat = cat->parent;
       break;
 
     cat = cat->parent;
@@ -454,62 +468,123 @@ void _xbt_log_event_log( xbt_log_event_t ev, const char *fmt, ...) {
   va_end(ev->ap);
 }
 
   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;
-    category->appender = xbt_log_default_appender;
-  } else {
-    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!
  */
 /*
  * 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;
-}
+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;
+  } else {
 
 
-void xbt_log_parent_set(xbt_log_category_t cat,
-                        xbt_log_category_t parent) {
+    if (!category->parent)
+      category->parent = &_XBT_LOGV(XBT_LOG_ROOT_CAT);
+    
+    xbt_log_parent_set(category, category->parent);
+  }
 
 
-  xbt_assert0(cat,"NULL category to be given a parent");
-  xbt_assert1(parent,"The parent category of %s is NULL",cat->name);
+  /* Apply the control */  
+  if (!xbt_log_settings)
+    return priority >= category->threshold;
+  
+  xbt_assert0(category,"NULL category");
+  xbt_assert(category->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,category->name)) {
+      
+      found = 1;
+      
+      xbt_log_threshold_set(category, setting->thresh);
+      xbt_dynar_cursor_rm(xbt_log_settings,&cursor);
 
 
-  /* unlink from current parent */
-  if (cat->threshold != xbt_log_priority_uninitialized) {
-    xbt_log_category_t* cpp = &parent->firstChild;
-    while(*cpp != cat && *cpp != NULL) {
-      cpp = &(*cpp)->nextSibling;
+      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_assert(*cpp == cat);
-    *cpp = cat->nextSibling;
   }
   }
-
-  /* Set new parent */
-  cat->parent = parent;
-  cat->nextSibling = parent->firstChild;
-  parent->firstChild = cat;
-
-  /* Make sure parent is initialized */
-  if (parent->threshold == xbt_log_priority_uninitialized) {
-    _cat_init(parent);
+  
+  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)",
+                      category->name,
+                      xbt_log_priority_names[category->threshold], category->threshold);
   }
     
   }
     
-  /* Reset priority */
-  cat->threshold = parent->threshold;
-  cat->isThreshInherited = 1;
-} /* log_setParent */
+  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);
+       
+       /* 
+        * if the threshold is initialized 
+        * unlink from current parent 
+        */
+       if(cat->threshold != xbt_log_priority_uninitialized){
+
+               xbt_log_category_t* cpp = &parent->firstChild;
+       
+               while(*cpp != cat && *cpp != NULL) {
+                       cpp = &(*cpp)->nextSibling;
+               }
+               
+               xbt_assert(*cpp == cat);
+               *cpp = cat->nextSibling;
+       }
+       
+       cat->parent = parent;
+       cat->nextSibling = parent->firstChild;
+       
+       parent->firstChild = cat;
+       
+       if (parent->threshold == xbt_log_priority_uninitialized){
+               
+         _xbt_log_cat_init(parent,
+                           xbt_log_priority_uninitialized/* ignored*/);
+       }
+       
+       cat->threshold = parent->threshold;
+       
+       cat->isThreshInherited = 1;
+       
+}
 
 static void _set_inherited_thresholds(xbt_log_category_t cat) {
 
 static void _set_inherited_thresholds(xbt_log_category_t cat) {
+       
+       
   xbt_log_category_t child = cat->firstChild;
   xbt_log_category_t child = cat->firstChild;
+  
   for( ; child != NULL; child = child->nextSibling) {
     if (child->isThreshInherited) {
       if (cat != &_XBT_LOGV(log))
   for( ; child != NULL; child = child->nextSibling) {
     if (child->isThreshInherited) {
       if (cat != &_XBT_LOGV(log))
@@ -519,36 +594,41 @@ static void _set_inherited_thresholds(xbt_log_category_t cat) {
       _set_inherited_thresholds(child);
     }
   }
       _set_inherited_thresholds(child);
     }
   }
+  
 }
 
 void xbt_log_threshold_set(xbt_log_category_t   cat,
                            e_xbt_log_priority_t threshold) {
   cat->threshold = threshold;
   cat->isThreshInherited = 0;
 }
 
 void xbt_log_threshold_set(xbt_log_category_t   cat,
                            e_xbt_log_priority_t threshold) {
   cat->threshold = threshold;
   cat->isThreshInherited = 0;
   _set_inherited_thresholds(cat);
   _set_inherited_thresholds(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;
   if (!*control_string) 
   const char *name, *dot, *eq;
   
   set->catname=NULL;
   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;
   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, " ");
 
   eq = control_string;
   control_string += strcspn(control_string, " ");
 
-  xbt_assert1(*dot == '.' && *eq == '=',
+  xbt_assert1(*dot == '.' && (*eq == '=' || *eq == ':'),
               "Invalid control string '%s'",control_string);
 
               "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;
     int i;
     char *neweq=xbt_strdup(eq+1);
     char *p=neweq-1;
@@ -560,72 +640,43 @@ static void _xbt_log_parse_setting(const char*        control_string,
     }
     
     DEBUG1("New priority name = %s",neweq);
     }
     
     DEBUG1("New priority name = %s",neweq);
-    for (i=0; i<xbt_log_priority_infinite-1; i++) {
+    for (i=0; i<xbt_log_priority_infinite; i++) {
       if (!strncmp(xbt_log_priority_names[i],neweq,p-eq)) {
        DEBUG1("This is priority %d",i);
        break;
       }
     }
       if (!strncmp(xbt_log_priority_names[i],neweq,p-eq)) {
        DEBUG1("This is priority %d",i);
        break;
       }
     }
-    if (i<xbt_log_priority_infinite-1) {
+    if (i<xbt_log_priority_infinite) {
       set->thresh= (e_xbt_log_priority_t) i;
     } else {
       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 {
     char buff[512];
     snprintf(buff,min(512,eq - dot - 1),"%s",dot+1);
     }
     free(neweq);
   } 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);
+    THROW1(arg_error,0,"Unknown setting of the log category: %s",buff);
   }
   set->catname=(char*)xbt_malloc(dot - name+1);
     
   }
   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);
   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;
   
 }
 
 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;
     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);
 }
 
 /**
 }
 
 /**
@@ -634,52 +685,58 @@ static void _cleanup_double_spaces(char *s) {
  *
  * Typically passed a command-line argument. The string has the syntax:
  *
  *
  * 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) 
  * and keyword is one of the following:
  *
  *    - thres: category's threshold priority. Possible values:
  *             TRACE,DEBUG,VERBOSE,INFO,WARNING,ERROR,CRITICAL
  *
  * where [category] is one the category names (see \ref XBT_log_cats for a complete list) 
  * and keyword is one of the following:
  *
  *    - thres: category's threshold priority. Possible values:
  *             TRACE,DEBUG,VERBOSE,INFO,WARNING,ERROR,CRITICAL
+ *    - add or additivity: whether the logging actions must be passed to 
+ *      the parent category. 
+ *      Possible values: 0, 1, yes, no.
+ *      Default value: yes.
  *             
  *             
- *
- * \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
  */
 void xbt_log_control_set(const char* control_string) {
   xbt_log_setting_t set;
  */
 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;
     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),
   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(control_string," ");
+  xbt_dynar_foreach(set_strings,cpt,str) {
+    xbt_str_trim(str,NULL);
+    if (str[0]=='\0') {
+      xbt_dynar_cursor_rm(set_strings,&cpt);
+    }
+  }
 
 
-  _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;
     
     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);
 
     TRY {
       cat = _xbt_log_cat_searchsub(&_XBT_LOGV(root),set->catname);
@@ -689,25 +746,27 @@ void xbt_log_control_set(const char* control_string) {
        RETHROW;
       xbt_ex_free(e);
       found = 0;
        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");
     } 
 
     if (found) {
       DEBUG0("Apply directly");
-      free(set->catname);
       xbt_log_threshold_set(cat,set->thresh);
       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) {
   cat->appender = app;
 }
 
 } 
 
 void xbt_log_appender_set(xbt_log_category_t cat, xbt_log_appender_t app) {
   cat->appender = app;
 }
 
+void xbt_log_additivity_set(xbt_log_category_t cat, int additivity) {
+  cat->additivity = additivity;
+}
+