Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
revalidate the simulator output after last change
[simgrid.git] / src / xbt / log.c
index 55fa192..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
@@ -338,14 +392,18 @@ 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;
@@ -354,9 +412,13 @@ static void _free_setting(void *s) {
   xbt_log_setting_t set=*(xbt_log_setting_t*)s;
   if (set) {
     free(set->catname);
+    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",
@@ -369,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
@@ -391,9 +453,11 @@ void xbt_log_init(int *argc,char **argv) {
        
        /* 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_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++){
@@ -403,7 +467,11 @@ void xbt_log_init(int *argc,char **argv) {
                    !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);
@@ -425,16 +493,15 @@ 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);
   }
-    
+  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);
@@ -444,20 +511,27 @@ 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");
+  _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) {
-      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);    
+      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)
@@ -468,6 +542,63 @@ 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. 
@@ -483,6 +614,7 @@ int _xbt_log_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;
+    category->layout = xbt_log_default_layout;
   } else {
 
     if (!category->parent)
@@ -506,21 +638,9 @@ int _xbt_log_cat_init(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);
     }
   }
   
@@ -535,7 +655,7 @@ int _xbt_log_cat_init(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;
@@ -582,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) {
@@ -613,6 +732,10 @@ static xbt_log_setting_t _xbt_log_parse_setting(const char* control_string) {
   const char *name, *dot, *eq;
   
   set->catname=NULL;
+  set->thresh = xbt_log_priority_uninitialized;
+  set->fmt = NULL;
+  set->additivity = -1;
+
   if (!*control_string) 
     return set;
   DEBUG1("Parse log setting '%s'",control_string);
@@ -653,10 +776,31 @@ static xbt_log_setting_t _xbt_log_parse_setting(const char* control_string) {
             "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);
-    THROW1(arg_error,0,"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);
     
@@ -687,16 +831,18 @@ static xbt_log_category_t _xbt_log_cat_searchsub(xbt_log_category_t cat,char *na
  *
  *      ( [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
  *    - add or additivity: whether the logging actions must be passed to 
  *      the parent category. 
- *      Possible values: 0, 1, yes, no.
+ *      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;
@@ -716,13 +862,7 @@ void xbt_log_control_set(const char* 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);
-    }
-  }
+  set_strings=xbt_str_split_quoted(control_string);
 
   if (xbt_dynar_length(set_strings) == 0) { /* vicious user! */
     xbt_dynar_free(&set_strings);
@@ -750,7 +890,7 @@ void xbt_log_control_set(const char* control_string) {
 
     if (found) {
       DEBUG0("Apply directly");
-      xbt_log_threshold_set(cat,set->thresh);
+      _xbt_log_cat_apply_set(cat,set);
       _free_setting((void*)&set);
     } else {
 
@@ -763,8 +903,30 @@ void xbt_log_control_set(const char* control_string) {
 } 
 
 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;