From: mquinson Date: Wed, 6 Jun 2007 13:28:06 +0000 (+0000) Subject: Allow to change the log layout format X-Git-Tag: v3.3~1798 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/d86319f97cfcd4f445d934cd5701654fcece4c97 Allow to change the log layout format git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@3562 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- diff --git a/include/xbt/log.h b/include/xbt/log.h index 44d4b79389..0516f7b3a5 100644 --- a/include/xbt/log.h +++ b/include/xbt/log.h @@ -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 */ diff --git a/src/xbt/log.c b/src/xbt/log.c index 34a9101fcf..332264e7f9 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 @@ -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 index 0000000000..0f86c80516 --- /dev/null +++ b/src/xbt/xbt_log_layout_format.c @@ -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 +#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; iap); + 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; +}