Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Allow to change the log layout format
authormquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Wed, 6 Jun 2007 13:28:06 +0000 (13:28 +0000)
committermquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Wed, 6 Jun 2007 13:28:06 +0000 (13:28 +0000)
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@3562 48e7efb5-ca39-0410-a469-dd3cf9ba447f

include/xbt/log.h
src/xbt/log.c
src/xbt/xbt_log_layout_format.c [new file with mode: 0644]

index 44d4b79..0516f7b 100644 (file)
@@ -101,7 +101,7 @@ typedef enum {
     XBT_EXPORT_NO_IMPORT(s_xbt_log_category_t) _XBT_LOGV(catName) = {       \
         &_XBT_LOGV(parent), 0, 0,                    \
         #catName, xbt_log_priority_uninitialized, 1, \
-        0, 1                                          \
+        0, 0, 1                                      \
     }
 /**
  * \ingroup XBT_log
@@ -240,6 +240,7 @@ struct xbt_log_category_s {
   int threshold;
   int isThreshInherited;
   xbt_log_appender_t appender;
+  xbt_log_layout_t layout;
   int additivity;
 };
 
@@ -247,7 +248,6 @@ struct xbt_log_appender_s {
   void (*do_append) (xbt_log_appender_t this_appender,
                     char *event);
   void (*free_) (xbt_log_appender_t this_);
-  xbt_log_layout_t layout;
   void *data;
 };
 
@@ -298,6 +298,17 @@ XBT_PUBLIC(void) xbt_log_parent_set(xbt_log_category_t cat,
  */
 XBT_PUBLIC(void) xbt_log_appender_set(xbt_log_category_t cat,
                                      xbt_log_appender_t app);
+/**
+ * \ingroup XBT_log_implem  
+ * \param cat the category (not only its name, but the variable)
+ * \param lay the layout
+ *
+ * Programatically sets the category's layout.
+ * (the prefered interface is throught xbt_log_control_set())
+ *
+ */
+XBT_PUBLIC(void) xbt_log_layout_set(xbt_log_category_t cat, 
+                                   xbt_log_layout_t lay);
 
 /**
  * \ingroup XBT_log_implem  
@@ -316,8 +327,9 @@ XBT_PUBLIC(void) xbt_log_additivity_set(xbt_log_category_t cat,
  *
  * This layout is not as flexible as the pattern one
  */
-XBT_PUBLIC(xbt_log_layout_t) xbt_log_layout_simple_new(void);
-XBT_PUBLIC(xbt_log_appender_t) xbt_log_appender_file_new(xbt_log_layout_t layout);
+XBT_PUBLIC(xbt_log_layout_t) xbt_log_layout_simple_new(char*arg);
+XBT_PUBLIC(xbt_log_layout_t) xbt_log_layout_format_new(char*arg);
+XBT_PUBLIC(xbt_log_appender_t) xbt_log_appender_file_new(char*arg);
 
 
 /* ********************************** */
@@ -336,6 +348,7 @@ extern XBT_IMPORT_NO_EXPORT(s_xbt_log_category_t) _XBT_LOGV(XBT_LOG_ROOT_CAT);
 XBT_LOG_EXTERNAL_CATEGORY(GRAS);
 
 extern xbt_log_appender_t xbt_log_default_appender;
+extern xbt_log_layout_t xbt_log_default_layout;
 
 /* ********************** */
 /* Public functions again */
index 34a9101..332264e 100644 (file)
@@ -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
@@ -347,6 +396,8 @@ xbt_log_layout_t xbt_log_default_layout = NULL; /* set in log_init */
 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;
@@ -355,6 +406,8 @@ 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);
   }
 }
@@ -511,21 +564,59 @@ 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);
+      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 (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"));
+       }
+      }
+
+      xbt_dynar_cursor_rm(xbt_log_settings,&cursor);
     }
   }
   
@@ -618,6 +709,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);
@@ -658,6 +753,27 @@ 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),"%s",dot+1);
@@ -692,16 +808,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;
@@ -779,7 +897,7 @@ void xbt_log_appender_set(xbt_log_category_t cat, xbt_log_appender_t app) {
 }
 void xbt_log_layout_set(xbt_log_category_t cat, xbt_log_layout_t lay) {
   if (!cat->appender) {
-    WARN1("No appender to category %s. Setting the file appender as default",
+    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));
   }
@@ -790,6 +908,7 @@ void xbt_log_layout_set(xbt_log_category_t cat, xbt_log_layout_t lay) {
     }
   }
   cat->layout = lay;
+  xbt_log_additivity_set(cat,0);
 }
 
 void xbt_log_additivity_set(xbt_log_category_t cat, int additivity) {
diff --git a/src/xbt/xbt_log_layout_format.c b/src/xbt/xbt_log_layout_format.c
new file mode 100644 (file)
index 0000000..0f86c80
--- /dev/null
@@ -0,0 +1,137 @@
+/* $Id$ */
+
+/* layout_simple - a dumb log layout                                        */
+
+/* Copyright (c) 2003, 2004 Martin Quinson. All rights reserved.            */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "portable.h" /* execinfo when available */
+#include "xbt/sysdep.h"
+#include "xbt/log.h"
+#include "gras/virtu.h"
+#include <stdio.h>
+#include "xbt/ex_interface.h" /* backtraces */
+
+extern const char *xbt_log_priority_names[7];
+
+
+static char *xbt_log_layout_format_doit(xbt_log_layout_t l,
+                                       xbt_log_event_t ev, 
+                                       const char *msg_fmt) {
+  static char res[2048];
+  static double begin_of_time = -1;
+  char *p,*q;  
+
+  if (begin_of_time<0) 
+    begin_of_time=gras_os_time();
+
+  p = res;
+  q = l->data;
+
+  while (*q != '\0') {
+    if (*q == '%') {
+      q++;
+      switch (*q) {
+      case '\0':
+       THROW1(arg_error,0,"Layout format (%s) ending with %%",(char*)l->data);
+      case '%':
+       *p++ = '%';
+       break;
+      case 'n': /* platform-dependant line separator (LOG4J compliant) */
+       p += sprintf(p,"\n");
+       break;
+      case ' ': /* plain space (SimGrid extension) */
+       p += sprintf(p," ");
+       break;
+
+      case 'c': /* category name; LOG4J compliant
+                  should accept a precision postfix to show the hierarchy */
+       p += sprintf(p,"%s",ev->cat->name); 
+       break;
+      case 'p': /* priority name; LOG4J compliant */   
+       p += sprintf(p, "%s", xbt_log_priority_names[ev->priority] );
+       break;
+
+      case 'h': /* host name; SimGrid extension */
+       p += sprintf(p, "%s", gras_os_myname());
+       break;
+      case 't': /* process name; LOG4J compliant (thread name) */
+       p += sprintf(p, "%s", xbt_procname());
+       break;
+      case 'i': /* process PID name; SimGrid extension */
+       p += sprintf(p, "%ld", gras_os_getpid());
+       break;
+
+      case 'F': /* file name; LOG4J compliant */
+       p += sprintf(p,"%s",ev->fileName);
+       break;
+      case 'l': /* location; LOG4J compliant */
+       p += sprintf(p, "%s:%d", ev->fileName, ev->lineNum);
+       break;
+      case 'L': /* line number; LOG4J compliant */
+       p += sprintf(p, "%d", ev->lineNum);
+       break;
+      case 'M': /* method (ie, function) name; LOG4J compliant */
+       p += sprintf(p, "%s", ev->functionName);
+       break;
+      case 'b': /* backtrace; called %throwable in LOG4J */
+      case 'B': /* short backtrace; called %throwable{short} in LOG4J */
+#if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
+       {
+         xbt_ex_t e;
+         int i;
+         
+         e.used     = backtrace((void**)e.bt,XBT_BACKTRACE_SIZE);
+         e.bt_strings = NULL;
+         xbt_ex_setup_backtrace(&e);
+         if (*q=='B')
+           p += sprintf(p,"%s",e.bt_strings[2]+8);
+         else
+           for (i=2; i<e.used; i++)
+             p += sprintf(p,"%s\n",e.bt_strings[i]+8);
+         
+         e.msg=NULL;
+         e.remote=0;
+         xbt_ex_free(e);
+       }
+#else
+       p+=sprintf(p,"(no backtrace on this arch)");
+#endif
+       break;
+
+      case 'd': /* date; LOG4J compliant */
+       p += sprintf(p,"%f", gras_os_time());
+       break;
+      case 'r': /* application age; LOG4J compliant */
+       p += sprintf(p,"%f", gras_os_time()-begin_of_time);
+       break;
+       
+      case 'm': /* user-provided message; LOG4J compliant */
+       p += vsprintf(p, msg_fmt, ev->ap);
+       break;
+
+      default:
+       THROW2(arg_error,0,"Unknown %%%c sequence in layout format (%s)",
+              *q,(char*)l->data);
+      }
+      q++;
+    } else {
+      *(p++) = *(q++);
+    }
+  }
+  *p = '\0';
+  return res;
+}
+
+static void xbt_log_layout_format_free(xbt_log_layout_t lay) {
+  free(lay->data);
+}
+xbt_log_layout_t xbt_log_layout_format_new(char *arg) {
+  xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t,1);
+  res->do_layout = xbt_log_layout_format_doit;
+  res->free_     = xbt_log_layout_format_free;
+  res->data = xbt_strdup((char*)arg);
+  return res;
+}