Logo AND Algorithmique Numérique Distribuée

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