Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Consider the time 0.0 of logs at initialisation time, and not at the first message.
[simgrid.git] / src / xbt / xbt_log_layout_format.c
1 /* $Id$ */
2
3 /* layout_simple - a dumb log layout                                        */
4
5 /* Copyright (c) 2003, 2004 Martin Quinson. All rights reserved.            */
6
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. */
9
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 */
16 #include <stdio.h>
17
18 extern const char *xbt_log_priority_names[8];
19
20 static double format_begin_of_time = -1;
21
22 #define append1(fmt,fmt2,elm)                                         \
23   do {                                                               \
24     if (precision == -1) {                                        \
25       xbt_strbuff_append(buff, tmp=bprintf(fmt,elm));            \
26       free(tmp);                                                 \
27     } else {                                                      \
28       xbt_strbuff_append(buff, tmp=bprintf(fmt2,precision,elm)); \
29       free(tmp);                                                 \
30       precision = -1;                                            \
31     }                                                         \
32   } while (0)
33 #define append2(fmt,elm,elm2)                                         \
34   do {                                                               \
35     xbt_strbuff_append(buff, tmp=bprintf(fmt,elm,elm2));          \
36     free(tmp);                                                    \
37     precision = -1;                                               \
38   } while (0)
39
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"                      \
42   "  where:\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"
48
49
50 static void xbt_log_layout_format_dynamic(xbt_log_layout_t l,
51                                           xbt_log_event_t ev,
52                                           const char *fmt,
53                                           xbt_log_appender_t app)
54 {
55   xbt_strbuff_t buff = xbt_strbuff_new();
56   int precision = -1;
57   char *q = l->data;
58   char *tmp;
59   char *tmp2;
60   int vres;                     /* shut gcc up, but ignored */
61
62   while (*q != '\0') {
63     if (*q == '%') {
64       q++;
65     handle_modifier:
66       switch (*q) {
67       case '\0':
68         fprintf(stderr, "Layout format (%s) ending with %%\n",
69                 (char *) l->data);
70         abort();
71       case '%':
72         xbt_strbuff_append(buff, "%");
73         break;
74       case 'n':                /* platform-dependant line separator (LOG4J compliant) */
75         xbt_strbuff_append(buff, "\n");
76         break;
77       case 'e':                /* plain space (SimGrid extension) */
78         xbt_strbuff_append(buff, " ");
79         break;
80
81       case '.':                /* precision specifyier */
82         q++;
83         q += sscanf(q, "%d", &precision);
84         goto handle_modifier;
85
86       case 'c':                /* category name; LOG4J compliant
87                                    should accept a precision postfix to show the hierarchy */
88         append1("%s", "%.*s", ev->cat->name);
89         break;
90       case 'p':                /* priority name; LOG4J compliant */
91         append1("%s", "%.*s", xbt_log_priority_names[ev->priority]);
92         break;
93
94       case 'h':                /* host name; SimGrid extension */
95         append1("%s", "%.*s", gras_os_myname());
96         break;
97       case 't':                /* thread name; LOG4J compliant */
98         append1("%s", "%.*s", xbt_thread_self_name());
99         break;
100       case 'P':                /* process name; SimGrid extension */
101         append1("%s", "%.*s", xbt_procname());
102         break;
103       case 'i':                /* process PID name; SimGrid extension */
104         append1("%d", "%.*d", (*xbt_getpid) ());
105         break;
106
107       case 'F':                /* file name; LOG4J compliant */
108         append1("%s", "%.*s", ev->fileName);
109         break;
110       case 'l':                /* location; LOG4J compliant */
111         append2("%s:%d", ev->fileName, ev->lineNum);
112         precision = -1;         /* Ignored */
113         break;
114       case 'L':                /* line number; LOG4J compliant */
115         append1("%d", "%.*d", ev->lineNum);
116         break;
117       case 'M':                /* method (ie, function) name; LOG4J compliant */
118         append1("%s", "%.*s", ev->functionName);
119         break;
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)
123         {
124           xbt_ex_t e;
125           int i;
126
127           e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
128           e.bt_strings = NULL;
129           e.msg = NULL;
130           e.remote = 0;
131           xbt_backtrace_current(&e);
132           if (*q == 'B') {
133             append1("%s", "%.*s", e.bt_strings[2] + 8);
134           } else {
135             for (i = 2; i < e.used; i++)
136               append1("%s\n", "%.*s\n", e.bt_strings[i] + 8);
137           }
138
139           xbt_ex_free(e);
140         }
141 #else
142         append1("%s", "%.*s", "(no backtrace on this arch)");
143 #endif
144         break;
145
146       case 'd':                /* date; LOG4J compliant */
147         append1("%f", "%.*f", gras_os_time());
148         break;
149       case 'r':                /* application age; LOG4J compliant */
150         append1("%f", "%.*f", gras_os_time() - format_begin_of_time);
151         break;
152
153       case 'm':                /* user-provided message; LOG4J compliant */
154         vres = vasprintf(&tmp2, fmt, ev->ap_copy);
155         append1("%s", "%.*s", tmp2);
156         free(tmp2);
157         break;
158
159       default:
160         fprintf(stderr, ERRMSG, *q, (char *) l->data);
161         abort();
162       }
163       q++;
164     } else {
165       char tmp2[2];
166       tmp2[0] = *(q++);
167       tmp2[1] = '\0';
168       xbt_strbuff_append(buff, tmp2);
169     }
170   }
171   app->do_append(app, buff->data);
172   xbt_strbuff_free(buff);
173 }
174
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); \
179   return;\
180   }
181 static void xbt_log_layout_format_doit(xbt_log_layout_t l,
182                                        xbt_log_event_t ev,
183                                        const char *msg_fmt,
184                                        xbt_log_appender_t app)
185 {
186   char *p, *q;
187   int precision = -1;
188
189
190   p = ev->buffer;
191   q = l->data;
192
193   while (*q != '\0') {
194     if (*q == '%') {
195       q++;
196     handle_modifier:
197       switch (*q) {
198       case '\0':
199         fprintf(stderr, "Layout format (%s) ending with %%\n",
200                 (char *) l->data);
201         abort();
202       case '%':
203         *p++ = '%';
204         break;
205       case 'n':                /* platform-dependant line separator (LOG4J compliant) */
206         p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "\n");
207         check_overflow;
208         break;
209       case 'e':                /* plain space (SimGrid extension) */
210         p += snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), " ");
211         check_overflow;
212         break;
213
214       case '.':                /* precision specifyier */
215         q++;
216         q += sscanf(q, "%d", &precision);
217         goto handle_modifier;
218
219       case 'c':                /* category name; LOG4J compliant
220                                    should accept a precision postfix to show the hierarchy */
221         if (precision == -1) {
222           p +=
223             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
224                      ev->cat->name);
225           check_overflow;
226         } else {
227           p +=
228             sprintf(p, "%.*s",
229                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
230                               precision), ev->cat->name);
231           check_overflow;
232           precision = -1;
233         }
234         break;
235       case 'p':                /* priority name; LOG4J compliant */
236         if (precision == -1) {
237           p +=
238             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
239                      xbt_log_priority_names[ev->priority]);
240           check_overflow;
241         } else {
242           p +=
243             sprintf(p, "%.*s",
244                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
245                               precision),
246                     xbt_log_priority_names[ev->priority]);
247           check_overflow;
248           precision = -1;
249         }
250         break;
251
252       case 'h':                /* host name; SimGrid extension */
253         if (precision == -1) {
254           p +=
255             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
256                      gras_os_myname());
257           check_overflow;
258         } else {
259           p +=
260             sprintf(p, "%.*s",
261                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
262                               precision), gras_os_myname());
263           check_overflow;
264           precision = -1;
265         }
266         break;
267       case 't':                /* thread name; LOG4J compliant */
268         if (precision == -1) {
269           p +=
270             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
271                      xbt_thread_self_name());
272           check_overflow;
273         } else {
274           p +=
275             sprintf(p, "%.*s",
276                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
277                               precision), xbt_thread_self_name());
278           check_overflow;
279           precision = -1;
280         }
281         break;
282       case 'P':                /* process name; SimGrid extension */
283         if (precision == -1) {
284           p +=
285             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
286                      xbt_procname());
287           check_overflow;
288         } else {
289           p +=
290             sprintf(p, "%.*s",
291                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
292                               precision), xbt_procname());
293           check_overflow;
294           precision = -1;
295         }
296         break;
297       case 'i':                /* process PID name; SimGrid extension */
298         if (precision == -1) {
299           p +=
300             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%d",
301                      (*xbt_getpid) ());
302           check_overflow;
303         } else {
304           p +=
305             sprintf(p, "%.*d",
306                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
307                               precision), (*xbt_getpid) ());
308           check_overflow;
309           precision = -1;
310         }
311         break;
312
313       case 'F':                /* file name; LOG4J compliant */
314         if (precision == -1) {
315           p +=
316             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
317                      ev->fileName);
318           check_overflow;
319         } else {
320           p +=
321             sprintf(p, "%.*s",
322                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
323                               precision), ev->fileName);
324           check_overflow;
325           precision = -1;
326         }
327         break;
328       case 'l':                /* location; LOG4J compliant */
329         if (precision == -1) {
330           p +=
331             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s:%d",
332                      ev->fileName, ev->lineNum);
333           check_overflow;
334         } else {
335           p +=
336             snprintf(p,
337                      (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
338                                precision), "%s:%d", ev->fileName,
339                      ev->lineNum);
340           check_overflow;
341           precision = -1;
342         }
343         break;
344       case 'L':                /* line number; LOG4J compliant */
345         if (precision == -1) {
346           p +=
347             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%d",
348                      ev->lineNum);
349           check_overflow;
350         } else {
351           p +=
352             sprintf(p, "%.*d",
353                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
354                               precision), ev->lineNum);
355           check_overflow;
356           precision = -1;
357         }
358         break;
359       case 'M':                /* method (ie, function) name; LOG4J compliant */
360         if (precision == -1) {
361           p +=
362             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
363                      ev->functionName);
364           check_overflow;
365         } else {
366           p +=
367             sprintf(p, "%.*s",
368                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
369                               precision), ev->functionName);
370           check_overflow;
371           precision = -1;
372         }
373         break;
374       case 'b':                /* backtrace; called %throwable in LOG4J */
375       case 'B':                /* short backtrace; called %throwable{short} in LOG4J */
376 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
377         {
378           xbt_ex_t e;
379           int i;
380
381           e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE);
382           e.bt_strings = NULL;
383           e.msg = NULL;
384           e.remote = 0;
385           xbt_backtrace_current(&e);
386           if (*q == 'B') {
387             if (precision == -1) {
388               p +=
389                 snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s",
390                          e.bt_strings[2] + 8);
391               check_overflow;
392             } else {
393               p +=
394                 sprintf(p, "%.*s",
395                         (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
396                                   precision), e.bt_strings[2] + 8);
397               check_overflow;
398               precision = -1;
399             }
400           } else {
401             for (i = 2; i < e.used; i++)
402               if (precision == -1) {
403                 p +=
404                   snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%s\n",
405                            e.bt_strings[i] + 8);
406                 check_overflow;
407               } else {
408                 p +=
409                   sprintf(p, "%.*s\n",
410                           (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
411                                     precision), e.bt_strings[i] + 8);
412                 check_overflow;
413                 precision = -1;
414               }
415           }
416
417           xbt_ex_free(e);
418         }
419 #else
420         p +=
421           snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer),
422                    "(no backtrace on this arch)");
423         check_overflow;
424 #endif
425         break;
426
427       case 'd':                /* date; LOG4J compliant */
428         if (precision == -1) {
429           p +=
430             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%f",
431                      gras_os_time());
432           check_overflow;
433         } else {
434           p +=
435             sprintf(p, "%.*f",
436                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
437                               precision), gras_os_time());
438           check_overflow;
439           precision = -1;
440         }
441         break;
442       case 'r':                /* application age; LOG4J compliant */
443         if (precision == -1) {
444           p +=
445             snprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), "%f",
446                      gras_os_time() - format_begin_of_time);
447           check_overflow;
448         } else {
449           p +=
450             sprintf(p, "%.*f",
451                     (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
452                               precision), gras_os_time() - format_begin_of_time);
453           check_overflow;
454           precision = -1;
455         }
456         break;
457
458       case 'm':                /* user-provided message; LOG4J compliant */
459         if (precision == -1) {
460           p +=
461             vsnprintf(p, XBT_LOG_BUFF_SIZE - (p - ev->buffer), msg_fmt,
462                       ev->ap);
463           check_overflow;
464         } else {
465           p +=
466             vsnprintf(p,
467                       (int) MIN(XBT_LOG_BUFF_SIZE - (p - ev->buffer),
468                                 precision), msg_fmt, ev->ap);
469           check_overflow;
470           precision = -1;
471         }
472         break;
473
474       default:
475         fprintf(stderr, ERRMSG, *q, (char *) l->data);
476         abort();
477       }
478       q++;
479     } else {
480       *(p++) = *(q++);
481       check_overflow;
482     }
483   }
484   *p = '\0';
485   app->do_append(app, ev->buffer);
486 }
487
488 static void xbt_log_layout_format_free(xbt_log_layout_t lay)
489 {
490   free(lay->data);
491 }
492
493 xbt_log_layout_t xbt_log_layout_format_new(char *arg)
494 {
495   xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t, 1);
496   res->do_layout = xbt_log_layout_format_doit;
497   res->free_ = xbt_log_layout_format_free;
498   res->data = xbt_strdup((char *) arg);
499
500   if (format_begin_of_time < 0)
501     format_begin_of_time = gras_os_time();
502   
503   return res;
504 }