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 append(data,letter) \
23 if (precision == -1 && length == -1) { \
24 tmp = bprintf("%" letter, data); \
25 } else if (precision == -1) { \
26 sprintf(tmpfmt,"%%%d" letter,length); \
27 tmp = bprintf(tmpfmt, data); \
29 } else if (length == -1) { \
30 tmp = bprintf("%.*" letter, precision, data);\
33 sprintf(tmpfmt,"%%%d.*" letter,length); \
34 tmp = bprintf(tmpfmt, precision, data); \
35 length = precision = -1; \
37 xbt_strbuff_append(buff,tmp);\
41 #define append_string(data) append(data, "s")
42 #define append_int(data) append(data, "d")
43 #define append_double(data) append(data, "f")
45 #define append2(fmt,elm,elm2) \
47 xbt_strbuff_append(buff, tmp=bprintf(fmt,elm,elm2)); \
52 #define ERRMSG "Unknown %%%c sequence in layout format (%s).\nKnown sequences:\n" \
53 " what: %%m: user message %%c: log category %%p: log priority\n" \
55 " source: %%F: file %%L: line %%M: function %%l: location (%%F:%%L)\n" \
56 " runtime: %%h: hostname %%t: thread %%P: process %%i: PID\n" \
57 " backtrace: %%b: full %%B: short\n" \
58 " when: %%d: date %%r: app. age\n" \
59 " other: %%%%: %% %%n: new line %%e: plain space\n"
62 static void xbt_log_layout_format_dynamic(xbt_log_layout_t l,
65 xbt_log_appender_t app)
67 xbt_strbuff_t buff = xbt_strbuff_new();
81 fprintf(stderr, "Layout format (%s) ending with %%\n",
85 xbt_strbuff_append(buff, "%");
87 case 'n': /* platform-dependant line separator (LOG4J compliant) */
88 xbt_strbuff_append(buff, "\n");
90 case 'e': /* plain space (SimGrid extension) */
91 xbt_strbuff_append(buff, " ");
94 case '.': /* precision specifyier */
96 sscanf(q, "%d", &precision);
97 q += (precision>9?2:1);
109 case '9': /* length modifier */
110 sscanf(q, "%d", &length);
112 goto handle_modifier;
114 case 'c': /* category name; LOG4J compliant
115 should accept a precision postfix to show the hierarchy */
116 append_string(ev->cat->name);
118 case 'p': /* priority name; LOG4J compliant */
119 append_string(xbt_log_priority_names[ev->priority]);
122 case 'h': /* host name; SimGrid extension */
123 append_string(gras_os_myname());
125 case 't': /* thread name; LOG4J compliant */
126 append_string(xbt_thread_self_name());
128 case 'P': /* process name; SimGrid extension */
129 append_string(xbt_procname());
131 case 'i': /* process PID name; SimGrid extension */
132 append_int((*xbt_getpid) ());
135 case 'F': /* file name; LOG4J compliant */
136 append_string(ev->fileName);
138 case 'l': /* location; LOG4J compliant */
139 append2("%s:%d", ev->fileName, ev->lineNum);
140 precision = -1; /* Ignored */
142 case 'L': /* line number; LOG4J compliant */
143 append_int(ev->lineNum);
145 case 'M': /* method (ie, function) name; LOG4J compliant */
146 append_string(ev->functionName);
148 case 'b': /* backtrace; called %throwable in LOG4J */
149 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
150 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
155 e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
159 xbt_backtrace_current(&e);
161 append_string(e.bt_strings[2] + 8);
163 for (i = 2; i < e.used; i++) {
164 append_string(e.bt_strings[i] + 8);
165 xbt_strbuff_append(buff, "\n");
172 append_string("(no backtrace on this arch)");
176 case 'd': /* date; LOG4J compliant */
177 append_double(gras_os_time());
179 case 'r': /* application age; LOG4J compliant */
180 append_double(gras_os_time() - format_begin_of_time);
183 case 'm': /* user-provided message; LOG4J compliant */
184 tmp2 = bvprintf(fmt, ev->ap_copy);
190 fprintf(stderr, ERRMSG, *q, (char *) l->data);
198 xbt_strbuff_append(buff, tmp2);
201 app->do_append(app, buff->data);
202 xbt_strbuff_free(buff);
205 #undef check_overflow
206 #define check_overflow \
207 if (p-ev->buffer > XBT_LOG_BUFF_SIZE) { /* buffer overflow */ \
208 xbt_log_layout_format_dynamic(l,ev,msg_fmt,app); \
212 #define show_it(data,letter) \
214 if (precision == -1 && length == -1) { \
215 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%" letter, data); \
216 } else if (precision == -1) { \
217 sprintf(tmpfmt,"%%%d" letter,length); \
218 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), tmpfmt, data); \
220 } else if (length == -1) { \
221 p += sprintf(p, "%.*" letter, \
222 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer), precision), \
226 sprintf(tmpfmt,"%%%d.%d" letter,length, \
227 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer), precision));\
228 p += sprintf(p, tmpfmt, data);\
229 length = precision = -1; \
234 #define show_string(data) show_it(data, "s")
235 #define show_int(data) show_it(data, "d")
236 #define show_double(data) show_it(data, "f")
238 static void xbt_log_layout_format_doit(xbt_log_layout_t l,
241 xbt_log_appender_t app)
258 fprintf(stderr, "Layout format (%s) ending with %%\n",
264 case 'n': /* platform-dependant line separator (LOG4J compliant) */
265 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "\n");
268 case 'e': /* plain space (SimGrid extension) */
269 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), " ");
273 case '.': /* precision specifyier */
275 sscanf(q, "%d", &precision);
276 q += (precision>9?2:1);
277 goto handle_modifier;
288 case '9': /* length modifier */
289 sscanf(q, "%d", &length);
291 goto handle_modifier;
293 case 'c': /* category name; LOG4J compliant
294 should accept a precision postfix to show the hierarchy */
295 show_string(ev->cat->name);
297 case 'p': /* priority name; LOG4J compliant */
298 show_string(xbt_log_priority_names[ev->priority]);
301 case 'h': /* host name; SimGrid extension */
302 show_string(gras_os_myname());
304 case 't': /* thread name; LOG4J compliant */
305 show_string(xbt_thread_self_name());
307 case 'P': /* process name; SimGrid extension */
308 show_string(xbt_procname());
310 case 'i': /* process PID name; SimGrid extension */
311 show_int((*xbt_getpid) ());
314 case 'F': /* file name; LOG4J compliant */
315 show_string(ev->fileName);
317 case 'l': /* location; LOG4J compliant */
318 if (precision == -1) {
319 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s:%d",
320 ev->fileName, ev->lineNum);
324 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
325 precision), "%s:%d", ev->fileName,
331 case 'L': /* line number; LOG4J compliant */
332 show_int(ev->lineNum);
334 case 'M': /* method (ie, function) name; LOG4J compliant */
335 show_string(ev->functionName);
337 case 'b': /* backtrace; called %throwable in LOG4J */
338 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
339 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
344 e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
348 xbt_backtrace_current(&e);
350 show_string(e.bt_strings[2] + 8);
352 for (i = 2; i < e.used; i++)
353 if (precision == -1) {
354 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer),
355 "%s\n", e.bt_strings[i] + 8);
358 p += sprintf(p, "%.*s\n",
359 (int) MIN(XBT_LOG_BUFF_SIZE -
360 (p - ev->buffer), precision),
361 e.bt_strings[i] + 8);
370 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer),
371 "(no backtrace on this arch)");
376 case 'd': /* date; LOG4J compliant */
377 show_double(gras_os_time());
379 case 'r': /* application age; LOG4J compliant */
380 show_double(gras_os_time() - format_begin_of_time);
383 case 'm': /* user-provided message; LOG4J compliant */
384 if (precision == -1) {
385 p += vsnprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), msg_fmt,
390 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
391 precision), msg_fmt, ev->ap);
398 fprintf(stderr, ERRMSG, *q, (char *) l->data);
408 app->do_append(app, ev->buffer);
411 static void xbt_log_layout_format_free(xbt_log_layout_t lay)
416 xbt_log_layout_t xbt_log_layout_format_new(char *arg)
418 xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t, 1);
419 res->do_layout = xbt_log_layout_format_doit;
420 res->free_ = xbt_log_layout_format_free;
421 res->data = xbt_strdup((char *) arg);
423 if (format_begin_of_time < 0)
424 format_begin_of_time = gras_os_time();