3 /* layout_simple - a dumb log layout */
5 /* Copyright (c) 2003, 2004 Martin Quinson. All rights reserved. */
7 /* This program is free software; you can redistribute it and/or modify it
8 * under the terms of the license (GNU LGPL) which comes with this package. */
10 #include "portable.h" /* execinfo when available */
11 #include "xbt/sysdep.h"
12 #include "xbt/strbuff.h"
13 #include "xbt/log_private.h"
14 #include "gras/virtu.h" /* gras_os_myname (KILLME) */
15 #include "xbt/synchro.h" /* xbt_thread_self_name */
18 extern const char *xbt_log_priority_names[8];
20 static double format_begin_of_time = -1;
22 #define append1(fmt,fmt2,elm) \
24 if (precision == -1) { \
25 xbt_strbuff_append(buff, tmp=bprintf(fmt,elm)); \
28 xbt_strbuff_append(buff, tmp=bprintf(fmt2,precision,elm)); \
33 #define append2(fmt,elm,elm2) \
35 xbt_strbuff_append(buff, tmp=bprintf(fmt,elm,elm2)); \
40 #define ERRMSG "Unknown %%%c sequence in layout format (%s).\nKnown sequences:\n" \
41 " what: %%m: user message %%c: log category %%p: log priority\n" \
43 " source: %%F: file %%L: line %%M: function %%l: location (%%F:%%L)\n" \
44 " runtime: %%h: hostname %%t: thread %%P: process %%i: PID\n" \
45 " backtrace: %%b: full %%B: short\n" \
46 " when: %%d: date %%r: app. age\n" \
47 " other: %%%%: %% %%n: new line %%e: plain space\n"
50 static void xbt_log_layout_format_dynamic(xbt_log_layout_t l,
53 xbt_log_appender_t app)
55 xbt_strbuff_t buff = xbt_strbuff_new();
60 int vres; /* shut gcc up, but ignored */
68 fprintf(stderr, "Layout format (%s) ending with %%\n",
72 xbt_strbuff_append(buff, "%");
74 case 'n': /* platform-dependant line separator (LOG4J compliant) */
75 xbt_strbuff_append(buff, "\n");
77 case 'e': /* plain space (SimGrid extension) */
78 xbt_strbuff_append(buff, " ");
81 case '.': /* precision specifyier */
83 q += sscanf(q, "%d", &precision);
86 case 'c': /* category name; LOG4J compliant
87 should accept a precision postfix to show the hierarchy */
88 append1("%s", "%.*s", ev->cat->name);
90 case 'p': /* priority name; LOG4J compliant */
91 append1("%s", "%.*s", xbt_log_priority_names[ev->priority]);
94 case 'h': /* host name; SimGrid extension */
95 append1("%s", "%.*s", gras_os_myname());
97 case 't': /* thread name; LOG4J compliant */
98 append1("%s", "%.*s", xbt_thread_self_name());
100 case 'P': /* process name; SimGrid extension */
101 append1("%s", "%.*s", xbt_procname());
103 case 'i': /* process PID name; SimGrid extension */
104 append1("%d", "%.*d", (*xbt_getpid) ());
107 case 'F': /* file name; LOG4J compliant */
108 append1("%s", "%.*s", ev->fileName);
110 case 'l': /* location; LOG4J compliant */
111 append2("%s:%d", ev->fileName, ev->lineNum);
112 precision = -1; /* Ignored */
114 case 'L': /* line number; LOG4J compliant */
115 append1("%d", "%.*d", ev->lineNum);
117 case 'M': /* method (ie, function) name; LOG4J compliant */
118 append1("%s", "%.*s", ev->functionName);
120 case 'b': /* backtrace; called %throwable in LOG4J */
121 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
122 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
127 e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
131 xbt_backtrace_current(&e);
133 append1("%s", "%.*s", e.bt_strings[2] + 8);
135 for (i = 2; i < e.used; i++)
136 append1("%s\n", "%.*s\n", e.bt_strings[i] + 8);
142 append1("%s", "%.*s", "(no backtrace on this arch)");
146 case 'd': /* date; LOG4J compliant */
147 append1("%f", "%.*f", gras_os_time());
149 case 'r': /* application age; LOG4J compliant */
150 append1("%f", "%.*f", gras_os_time() - format_begin_of_time);
153 case 'm': /* user-provided message; LOG4J compliant */
154 vres = vasprintf(&tmp2, fmt, ev->ap_copy);
155 append1("%s", "%.*s", tmp2);
160 fprintf(stderr, ERRMSG, *q, (char *) l->data);
168 xbt_strbuff_append(buff, tmp2);
171 app->do_append(app, buff->data);
172 xbt_strbuff_free(buff);
175 #undef check_overflow
176 #define check_overflow \
177 if (p-ev->buffer > XBT_LOG_BUFF_SIZE) { /* buffer overflow */ \
178 xbt_log_layout_format_dynamic(l,ev,msg_fmt,app); \
181 static void xbt_log_layout_format_doit(xbt_log_layout_t l,
184 xbt_log_appender_t app)
189 if (format_begin_of_time < 0)
190 format_begin_of_time = gras_os_time();
201 fprintf(stderr, "Layout format (%s) ending with %%\n",
207 case 'n': /* platform-dependant line separator (LOG4J compliant) */
208 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "\n");
211 case 'e': /* plain space (SimGrid extension) */
212 p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), " ");
216 case '.': /* precision specifyier */
218 q += sscanf(q, "%d", &precision);
219 goto handle_modifier;
221 case 'c': /* category name; LOG4J compliant
222 should accept a precision postfix to show the hierarchy */
223 if (precision == -1) {
225 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
231 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
232 precision), ev->cat->name);
237 case 'p': /* priority name; LOG4J compliant */
238 if (precision == -1) {
240 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
241 xbt_log_priority_names[ev->priority]);
246 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
248 xbt_log_priority_names[ev->priority]);
254 case 'h': /* host name; SimGrid extension */
255 if (precision == -1) {
257 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
263 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
264 precision), gras_os_myname());
269 case 't': /* thread name; LOG4J compliant */
270 if (precision == -1) {
272 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
273 xbt_thread_self_name());
278 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
279 precision), xbt_thread_self_name());
284 case 'P': /* process name; SimGrid extension */
285 if (precision == -1) {
287 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
293 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
294 precision), xbt_procname());
299 case 'i': /* process PID name; SimGrid extension */
300 if (precision == -1) {
302 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%d",
308 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
309 precision), (*xbt_getpid) ());
315 case 'F': /* file name; LOG4J compliant */
316 if (precision == -1) {
318 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
324 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
325 precision), ev->fileName);
330 case 'l': /* location; LOG4J compliant */
331 if (precision == -1) {
333 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s:%d",
334 ev->fileName, ev->lineNum);
339 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
340 precision), "%s:%d", ev->fileName,
346 case 'L': /* line number; LOG4J compliant */
347 if (precision == -1) {
349 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%d",
355 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
356 precision), ev->lineNum);
361 case 'M': /* method (ie, function) name; LOG4J compliant */
362 if (precision == -1) {
364 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
370 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
371 precision), ev->functionName);
376 case 'b': /* backtrace; called %throwable in LOG4J */
377 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
378 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
383 e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
387 xbt_backtrace_current(&e);
389 if (precision == -1) {
391 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
392 e.bt_strings[2] + 8);
397 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
398 precision), e.bt_strings[2] + 8);
403 for (i = 2; i < e.used; i++)
404 if (precision == -1) {
406 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s\n",
407 e.bt_strings[i] + 8);
412 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
413 precision), e.bt_strings[i] + 8);
423 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer),
424 "(no backtrace on this arch)");
429 case 'd': /* date; LOG4J compliant */
430 if (precision == -1) {
432 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%f",
438 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
439 precision), gras_os_time());
444 case 'r': /* application age; LOG4J compliant */
445 if (precision == -1) {
447 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%f",
448 gras_os_time() - format_begin_of_time);
453 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
454 precision), gras_os_time() - format_begin_of_time);
460 case 'm': /* user-provided message; LOG4J compliant */
461 if (precision == -1) {
463 vsnprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), msg_fmt,
469 (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
470 precision), msg_fmt, ev->ap);
477 fprintf(stderr, ERRMSG, *q, (char *) l->data);
487 app->do_append(app, ev->buffer);
490 static void xbt_log_layout_format_free(xbt_log_layout_t lay)
495 xbt_log_layout_t xbt_log_layout_format_new(char *arg)
497 xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t, 1);
498 res->do_layout = xbt_log_layout_format_doit;
499 res->free_ = xbt_log_layout_format_free;
500 res->data = xbt_strdup((char *) arg);