1 /* layout_simple - a dumb log layout */
3 /* Copyright (c) 2003, 2004 Martin Quinson. All rights reserved. */
5 /* This program is free software; you can redistribute it and/or modify it
6 * under the terms of the license (GNU LGPL) which comes with this package. */
8 #include "portable.h" /* execinfo when available */
9 #include "xbt/sysdep.h"
10 #include "xbt/strbuff.h"
11 #include "xbt/log_private.h"
12 #include "gras/virtu.h" /* gras_os_myname (KILLME) */
13 #include "xbt/synchro.h" /* xbt_thread_self_name */
16 extern const char *xbt_log_priority_names[8];
18 static double format_begin_of_time = -1;
20 #define append1(fmt,fmt2,elm) \
22 if (precision == -1) { \
23 xbt_strbuff_append(buff, tmp=bprintf(fmt,elm)); \
26 xbt_strbuff_append(buff, tmp=bprintf(fmt2,precision,elm)); \
31 #define append2(fmt,elm,elm2) \
33 xbt_strbuff_append(buff, tmp=bprintf(fmt,elm,elm2)); \
38 #define ERRMSG "Unknown %%%c sequence in layout format (%s).\nKnown sequences:\n" \
39 " what: %%m: user message %%c: log category %%p: log priority\n" \
41 " source: %%F: file %%L: line %%M: function %%l: location (%%F:%%L)\n" \
42 " runtime: %%h: hostname %%t: thread %%P: process %%i: PID\n" \
43 " backtrace: %%b: full %%B: short\n" \
44 " when: %%d: date %%r: app. age\n" \
45 " other: %%%%: %% %%n: new line %%e: plain space\n"
48 static void xbt_log_layout_format_dynamic(xbt_log_layout_t l,
51 xbt_log_appender_t app)
53 xbt_strbuff_t buff = xbt_strbuff_new();
58 int vres; /* shut gcc up, but ignored */
66 fprintf(stderr, "Layout format (%s) ending with %%\n",
70 xbt_strbuff_append(buff, "%");
72 case 'n': /* platform-dependant line separator (LOG4J compliant) */
73 xbt_strbuff_append(buff, "\n");
75 case 'e': /* plain space (SimGrid extension) */
76 xbt_strbuff_append(buff, " ");
79 case '.': /* precision specifyier */
81 q += sscanf(q, "%d", &precision);
84 case 'c': /* category name; LOG4J compliant
85 should accept a precision postfix to show the hierarchy */
86 append1("%s", "%.*s", ev->cat->name);
88 case 'p': /* priority name; LOG4J compliant */
89 append1("%s", "%.*s", xbt_log_priority_names[ev->priority]);
92 case 'h': /* host name; SimGrid extension */
93 append1("%s", "%.*s", gras_os_myname());
95 case 't': /* thread name; LOG4J compliant */
96 append1("%s", "%.*s", xbt_thread_self_name());
98 case 'P': /* process name; SimGrid extension */
99 append1("%s", "%.*s", xbt_procname());
101 case 'i': /* process PID name; SimGrid extension */
102 append1("%d", "%.*d", (*xbt_getpid) ());
105 case 'F': /* file name; LOG4J compliant */
106 append1("%s", "%.*s", ev->fileName);
108 case 'l': /* location; LOG4J compliant */
109 append2("%s:%d", ev->fileName, ev->lineNum);
110 precision = -1; /* Ignored */
112 case 'L': /* line number; LOG4J compliant */
113 append1("%d", "%.*d", ev->lineNum);
115 case 'M': /* method (ie, function) name; LOG4J compliant */
116 append1("%s", "%.*s", ev->functionName);
118 case 'b': /* backtrace; called %throwable in LOG4J */
119 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
120 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
125 e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
129 xbt_backtrace_current(&e);
131 append1("%s", "%.*s", e.bt_strings[2] + 8);
133 for (i = 2; i < e.used; i++)
134 append1("%s\n", "%.*s\n", e.bt_strings[i] + 8);
140 append1("%s", "%.*s", "(no backtrace on this arch)");
144 case 'd': /* date; LOG4J compliant */
145 append1("%f", "%.*f", gras_os_time());
147 case 'r': /* application age; LOG4J compliant */
148 append1("%f", "%.*f", gras_os_time() - format_begin_of_time);
151 case 'm': /* user-provided message; LOG4J compliant */
152 vres = vasprintf(&tmp2, fmt, ev->ap_copy);
153 append1("%s", "%.*s", tmp2);
158 fprintf(stderr, ERRMSG, *q, (char *) l->data);
166 xbt_strbuff_append(buff, tmp2);
169 app->do_append(app, buff->data);
170 xbt_strbuff_free(buff);
173 #undef check_overflow
174 #define check_overflow \
175 if (p-ev->buffer > XBT_LOG_BUFF_SIZE) { /* buffer overflow */ \
176 xbt_log_layout_format_dynamic(l,ev,msg_fmt,app); \
179 static void xbt_log_layout_format_doit(xbt_log_layout_t l,
182 xbt_log_appender_t app)
197 fprintf(stderr, "Layout format (%s) ending with %%\n",
203 case 'n': /* platform-dependant line separator (LOG4J compliant) */
204 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "\n");
207 case 'e': /* plain space (SimGrid extension) */
208 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), " ");
212 case '.': /* precision specifyier */
214 q += sscanf(q, "%d", &precision);
215 goto handle_modifier;
217 case 'c': /* category name; LOG4J compliant
218 should accept a precision postfix to show the hierarchy */
219 if (precision == -1) {
221 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
227 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
228 precision), ev->cat->name);
233 case 'p': /* priority name; LOG4J compliant */
234 if (precision == -1) {
236 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
237 xbt_log_priority_names[ev->priority]);
242 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
244 xbt_log_priority_names[ev->priority]);
250 case 'h': /* host name; SimGrid extension */
251 if (precision == -1) {
253 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
259 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
260 precision), gras_os_myname());
265 case 't': /* thread name; LOG4J compliant */
266 if (precision == -1) {
268 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
269 xbt_thread_self_name());
274 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
275 precision), xbt_thread_self_name());
280 case 'P': /* process name; SimGrid extension */
281 if (precision == -1) {
283 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
289 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
290 precision), xbt_procname());
295 case 'i': /* process PID name; SimGrid extension */
296 if (precision == -1) {
298 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%d",
304 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
305 precision), (*xbt_getpid) ());
311 case 'F': /* file name; LOG4J compliant */
312 if (precision == -1) {
314 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
320 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
321 precision), ev->fileName);
326 case 'l': /* location; LOG4J compliant */
327 if (precision == -1) {
329 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s:%d",
330 ev->fileName, ev->lineNum);
335 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
336 precision), "%s:%d", ev->fileName,
342 case 'L': /* line number; LOG4J compliant */
343 if (precision == -1) {
345 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%d",
351 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
352 precision), ev->lineNum);
357 case 'M': /* method (ie, function) name; LOG4J compliant */
358 if (precision == -1) {
360 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
366 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
367 precision), ev->functionName);
372 case 'b': /* backtrace; called %throwable in LOG4J */
373 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
374 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
379 e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
383 xbt_backtrace_current(&e);
385 if (precision == -1) {
387 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
388 e.bt_strings[2] + 8);
393 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
394 precision), e.bt_strings[2] + 8);
399 for (i = 2; i < e.used; i++)
400 if (precision == -1) {
402 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s\n",
403 e.bt_strings[i] + 8);
408 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
409 precision), e.bt_strings[i] + 8);
419 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer),
420 "(no backtrace on this arch)");
425 case 'd': /* date; LOG4J compliant */
426 if (precision == -1) {
428 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%f",
434 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
435 precision), gras_os_time());
440 case 'r': /* application age; LOG4J compliant */
441 if (precision == -1) {
443 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%f",
444 gras_os_time() - format_begin_of_time);
449 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
450 precision), gras_os_time() - format_begin_of_time);
456 case 'm': /* user-provided message; LOG4J compliant */
457 if (precision == -1) {
459 vsnprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), msg_fmt,
465 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
466 precision), msg_fmt, ev->ap);
473 fprintf(stderr, ERRMSG, *q, (char *) l->data);
483 app->do_append(app, ev->buffer);
486 static void xbt_log_layout_format_free(xbt_log_layout_t lay)
491 xbt_log_layout_t xbt_log_layout_format_new(char *arg)
493 xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t, 1);
494 res->do_layout = xbt_log_layout_format_doit;
495 res->free_ = xbt_log_layout_format_free;
496 res->data = xbt_strdup((char *) arg);
498 if (format_begin_of_time < 0)
499 format_begin_of_time = gras_os_time();