1 /* layout_simple - a dumb log layout */
3 /* Copyright (c) 2007, 2008, 2009, 2010. The SimGrid Team.
4 * All rights reserved. */
6 /* This program is free software; you can redistribute it and/or modify it
7 * under the terms of the license (GNU LGPL) which comes with this package. */
9 #include "portable.h" /* execinfo when available */
10 #include "xbt/sysdep.h"
11 #include "xbt/strbuff.h"
12 #include "xbt/log_private.h"
13 #include "gras/virtu.h" /* gras_os_myname (KILLME) */
14 #include "xbt/synchro.h" /* xbt_thread_self_name */
17 extern const char *xbt_log_priority_names[8];
19 static double format_begin_of_time = -1;
21 #define append1(fmt,fmt2,elm) \
23 if (precision == -1) { \
24 xbt_strbuff_append(buff, tmp=bprintf(fmt,elm)); \
27 xbt_strbuff_append(buff, tmp=bprintf(fmt2,precision,elm)); \
32 #define append2(fmt,elm,elm2) \
34 xbt_strbuff_append(buff, tmp=bprintf(fmt,elm,elm2)); \
39 #define ERRMSG "Unknown %%%c sequence in layout format (%s).\nKnown sequences:\n" \
40 " what: %%m: user message %%c: log category %%p: log priority\n" \
42 " source: %%F: file %%L: line %%M: function %%l: location (%%F:%%L)\n" \
43 " runtime: %%h: hostname %%t: thread %%P: process %%i: PID\n" \
44 " backtrace: %%b: full %%B: short\n" \
45 " when: %%d: date %%r: app. age\n" \
46 " other: %%%%: %% %%n: new line %%e: plain space\n"
49 static void xbt_log_layout_format_dynamic(xbt_log_layout_t l,
52 xbt_log_appender_t app)
54 xbt_strbuff_t buff = xbt_strbuff_new();
59 int vres; /* shut gcc up, but ignored */
67 fprintf(stderr, "Layout format (%s) ending with %%\n",
71 xbt_strbuff_append(buff, "%");
73 case 'n': /* platform-dependant line separator (LOG4J compliant) */
74 xbt_strbuff_append(buff, "\n");
76 case 'e': /* plain space (SimGrid extension) */
77 xbt_strbuff_append(buff, " ");
80 case '.': /* precision specifyier */
82 q += sscanf(q, "%d", &precision);
85 case 'c': /* category name; LOG4J compliant
86 should accept a precision postfix to show the hierarchy */
87 append1("%s", "%.*s", ev->cat->name);
89 case 'p': /* priority name; LOG4J compliant */
90 append1("%s", "%.*s", xbt_log_priority_names[ev->priority]);
93 case 'h': /* host name; SimGrid extension */
94 append1("%s", "%.*s", gras_os_myname());
96 case 't': /* thread name; LOG4J compliant */
97 append1("%s", "%.*s", xbt_thread_self_name());
99 case 'P': /* process name; SimGrid extension */
100 append1("%s", "%.*s", xbt_procname());
102 case 'i': /* process PID name; SimGrid extension */
103 append1("%d", "%.*d", (*xbt_getpid) ());
106 case 'F': /* file name; LOG4J compliant */
107 append1("%s", "%.*s", ev->fileName);
109 case 'l': /* location; LOG4J compliant */
110 append2("%s:%d", ev->fileName, ev->lineNum);
111 precision = -1; /* Ignored */
113 case 'L': /* line number; LOG4J compliant */
114 append1("%d", "%.*d", ev->lineNum);
116 case 'M': /* method (ie, function) name; LOG4J compliant */
117 append1("%s", "%.*s", ev->functionName);
119 case 'b': /* backtrace; called %throwable in LOG4J */
120 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
121 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
126 e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
130 xbt_backtrace_current(&e);
132 append1("%s", "%.*s", e.bt_strings[2] + 8);
134 for (i = 2; i < e.used; i++)
135 append1("%s\n", "%.*s\n", e.bt_strings[i] + 8);
141 append1("%s", "%.*s", "(no backtrace on this arch)");
145 case 'd': /* date; LOG4J compliant */
146 append1("%f", "%.*f", gras_os_time());
148 case 'r': /* application age; LOG4J compliant */
149 append1("%f", "%.*f", gras_os_time() - format_begin_of_time);
152 case 'm': /* user-provided message; LOG4J compliant */
153 vres = vasprintf(&tmp2, fmt, ev->ap_copy);
154 append1("%s", "%.*s", tmp2);
159 fprintf(stderr, ERRMSG, *q, (char *) l->data);
167 xbt_strbuff_append(buff, tmp2);
170 app->do_append(app, buff->data);
171 xbt_strbuff_free(buff);
174 #undef check_overflow
175 #define check_overflow \
176 if (p-ev->buffer > XBT_LOG_BUFF_SIZE) { /* buffer overflow */ \
177 xbt_log_layout_format_dynamic(l,ev,msg_fmt,app); \
180 static void xbt_log_layout_format_doit(xbt_log_layout_t l,
183 xbt_log_appender_t app)
198 fprintf(stderr, "Layout format (%s) ending with %%\n",
204 case 'n': /* platform-dependant line separator (LOG4J compliant) */
205 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "\n");
208 case 'e': /* plain space (SimGrid extension) */
209 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), " ");
213 case '.': /* precision specifyier */
215 q += sscanf(q, "%d", &precision);
216 goto handle_modifier;
218 case 'c': /* category name; LOG4J compliant
219 should accept a precision postfix to show the hierarchy */
220 if (precision == -1) {
222 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
228 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
229 precision), ev->cat->name);
234 case 'p': /* priority name; LOG4J compliant */
235 if (precision == -1) {
237 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
238 xbt_log_priority_names[ev->priority]);
243 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
245 xbt_log_priority_names[ev->priority]);
251 case 'h': /* host name; SimGrid extension */
252 if (precision == -1) {
254 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
260 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
261 precision), gras_os_myname());
266 case 't': /* thread name; LOG4J compliant */
267 if (precision == -1) {
269 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
270 xbt_thread_self_name());
275 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
276 precision), xbt_thread_self_name());
281 case 'P': /* process name; SimGrid extension */
282 if (precision == -1) {
284 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
290 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
291 precision), xbt_procname());
296 case 'i': /* process PID name; SimGrid extension */
297 if (precision == -1) {
299 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%d",
305 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
306 precision), (*xbt_getpid) ());
312 case 'F': /* file name; LOG4J compliant */
313 if (precision == -1) {
315 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
321 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
322 precision), ev->fileName);
327 case 'l': /* location; LOG4J compliant */
328 if (precision == -1) {
330 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s:%d",
331 ev->fileName, ev->lineNum);
336 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
337 precision), "%s:%d", ev->fileName,
343 case 'L': /* line number; LOG4J compliant */
344 if (precision == -1) {
346 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%d",
352 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
353 precision), ev->lineNum);
358 case 'M': /* method (ie, function) name; LOG4J compliant */
359 if (precision == -1) {
361 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
367 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
368 precision), ev->functionName);
373 case 'b': /* backtrace; called %throwable in LOG4J */
374 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
375 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
380 e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
384 xbt_backtrace_current(&e);
386 if (precision == -1) {
388 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
389 e.bt_strings[2] + 8);
394 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
395 precision), e.bt_strings[2] + 8);
400 for (i = 2; i < e.used; i++)
401 if (precision == -1) {
403 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s\n",
404 e.bt_strings[i] + 8);
409 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
410 precision), e.bt_strings[i] + 8);
420 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer),
421 "(no backtrace on this arch)");
426 case 'd': /* date; LOG4J compliant */
427 if (precision == -1) {
429 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%f",
435 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
436 precision), gras_os_time());
441 case 'r': /* application age; LOG4J compliant */
442 if (precision == -1) {
444 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%f",
445 gras_os_time() - format_begin_of_time);
450 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
451 precision), gras_os_time() - format_begin_of_time);
457 case 'm': /* user-provided message; LOG4J compliant */
458 if (precision == -1) {
460 vsnprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), msg_fmt,
466 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
467 precision), msg_fmt, ev->ap);
474 fprintf(stderr, ERRMSG, *q, (char *) l->data);
484 app->do_append(app, ev->buffer);
487 static void xbt_log_layout_format_free(xbt_log_layout_t lay)
492 xbt_log_layout_t xbt_log_layout_format_new(char *arg)
494 xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t, 1);
495 res->do_layout = xbt_log_layout_format_doit;
496 res->free_ = xbt_log_layout_format_free;
497 res->data = xbt_strdup((char *) arg);
499 if (format_begin_of_time < 0)
500 format_begin_of_time = gras_os_time();