#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 "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
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
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, #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
+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>
+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, #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
+instead.
+
\section log_API_example 2.5 Example of use
Here is a more complete example:
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 >= INFO. * /
CWARN2(VSS, "Low fuel level.");
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
- 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
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",
"CRITICAL"
};
-s_xbt_log_category_t _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
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");
+/** @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;
-
- /* 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(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],"--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");
-}
-
-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);
- }
-
+ 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;
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);
+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);
+ }
}
- _apply_control(category);
-}
+ 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) {
-
- _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;
+ category->layout = xbt_log_default_layout;
+ } 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_cat_apply_set(category,setting);
- /* 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_dynar_cursor_rm(xbt_log_settings,&cursor);
}
- 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) {
+
xbt_log_category_t child = cat->firstChild;
+
for( ; child != NULL; child = child->nextSibling) {
if (child->isThreshInherited) {
if (cat != &_XBT_LOGV(log))
_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;
+
_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;
+ 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(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;
}
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 (i<xbt_log_priority_infinite-1) {
- set->thresh=i;
+ 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) {
- 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);
}
/**
*
* 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);
- _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;
- 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);
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;
+}