Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Do not truncate the output on large messages, but switch to a dynamically allocated...
[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[7];
19
20 static double 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 static void xbt_log_layout_format_dynamic(xbt_log_layout_t l,
41                                           xbt_log_event_t ev,
42                                           const char*fmt,
43                                           xbt_log_appender_t app) {
44   xbt_strbuff_t buff = xbt_strbuff_new();   
45   int precision=-1;
46   char *q = l->data;
47   char *tmp;
48   char *tmp2;
49
50   while (*q != '\0') {
51     if (*q == '%') {
52       q++;
53        handle_modifier:
54       switch (*q) {
55       case '\0':
56         fprintf(stderr,"Layout format (%s) ending with %%\n",(char*)l->data);
57         abort();
58       case '%':
59         xbt_strbuff_append(buff,"%");
60         break;
61       case 'n': /* platform-dependant line separator (LOG4J compliant) */
62         xbt_strbuff_append(buff,"\n");
63         break;
64       case 'e': /* plain space (SimGrid extension) */
65         xbt_strbuff_append(buff," ");
66         break;
67          
68       case '.': /* precision specifyier */
69         q++;
70         q += sscanf(q,"%d",&precision);
71         goto handle_modifier;
72
73       case 'c': /* category name; LOG4J compliant
74                    should accept a precision postfix to show the hierarchy */
75         append1("%s","%.*s",ev->cat->name);
76         break;
77       case 'p': /* priority name; LOG4J compliant */    
78         append1("%s","%.*s",xbt_log_priority_names[ev->priority]);
79         break;
80
81       case 'h': /* host name; SimGrid extension */
82         append1("%s","%.*s",gras_os_myname());
83         break;
84       case 't': /* thread name; LOG4J compliant */
85         append1("%s","%.*s",xbt_thread_self_name());
86         break;
87       case 'P': /* process name; SimGrid extension */
88         append1("%s","%.*s",xbt_procname());
89         break;
90       case 'i': /* process PID name; SimGrid extension */
91         append1("%d","%.*d",(*xbt_getpid)());
92         break;
93    
94       case 'F': /* file name; LOG4J compliant */
95         append1("%s","%.*s",ev->fileName);
96         break;
97       case 'l': /* location; LOG4J compliant */
98         append2("%s:%d",ev->fileName,ev->lineNum);
99         precision = -1; /* Ignored */
100         break;
101       case 'L': /* line number; LOG4J compliant */
102         append1("%d","%.*d",ev->lineNum);
103         break;
104       case 'M': /* method (ie, function) name; LOG4J compliant */
105         append1("%s","%.*s",ev->functionName);
106         break;
107       case 'b': /* backtrace; called %throwable in LOG4J */
108       case 'B': /* short backtrace; called %throwable{short} in LOG4J */
109 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
110         {
111           xbt_ex_t e;
112           int i;
113           
114           e.used     = backtrace((void**)e.bt,XBT_BACKTRACE_SIZE);
115           e.bt_strings = NULL;
116           e.msg=NULL;
117           e.remote=0;
118           xbt_backtrace_current(&e);
119           if (*q=='B') {
120              append1("%s","%.*s",e.bt_strings[2]+8);
121           } else {
122             for (i=2; i<e.used; i++)
123               append1("%s\n","%.*s\n",e.bt_strings[i]+8);
124           }
125            
126           xbt_ex_free(e);
127         }
128 #else
129         append1("%s","%.*s","(no backtrace on this arch)");
130 #endif
131         break;
132
133       case 'd': /* date; LOG4J compliant */
134         append1("%f","%.*f", gras_os_time());
135         break;
136       case 'r': /* application age; LOG4J compliant */
137         append1("%f","%.*f", gras_os_time()-begin_of_time);
138         break;
139         
140       case 'm': /* user-provided message; LOG4J compliant */
141         vasprintf(&tmp2, fmt, ev->ap_copy);
142         append1("%s","%.*s",tmp2);
143         free(tmp2);
144         break;
145
146       default:
147         fprintf(stderr,"Unknown %%%c sequence in layout format (%s)\n",
148                 *q,(char*)l->data);
149         abort();
150       }
151       q++;
152     } else {
153       char tmp2[2];
154       tmp2[0] = *(q++);
155       tmp2[1] = '\0';
156       xbt_strbuff_append(buff,tmp2);
157     }
158   }
159   app->do_append(app,buff->data);
160   xbt_strbuff_free(buff);
161 }
162
163 #define check_overflow \
164   if (p-ev->buffer > XBT_LOG_BUFF_SIZE) { /* buffer overflow */ \
165      xbt_log_layout_format_dynamic(l,ev,msg_fmt,app); \
166      return;\
167   } 
168 static void xbt_log_layout_format_doit(xbt_log_layout_t l,
169                                        xbt_log_event_t ev, 
170                                        const char *msg_fmt,
171                                        xbt_log_appender_t app) {
172   char *p,*q;
173   int precision=-1;
174
175   if (begin_of_time<0) 
176     begin_of_time=gras_os_time();
177
178   p = ev->buffer;
179   q = l->data;
180
181   while (*q != '\0') {
182     if (*q == '%') {
183       q++;
184        handle_modifier:
185       switch (*q) {
186       case '\0':
187         fprintf(stderr,"Layout format (%s) ending with %%\n",(char*)l->data);
188         abort();
189       case '%':
190         *p++ = '%';
191         break;
192       case 'n': /* platform-dependant line separator (LOG4J compliant) */
193         p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"\n");
194         check_overflow;
195         break;
196       case 'e': /* plain space (SimGrid extension) */
197         p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer)," ");
198         check_overflow;
199         break;
200          
201       case '.': /* precision specifyier */
202         q++;
203         q += sscanf(q,"%d",&precision);
204         goto handle_modifier;
205
206       case 'c': /* category name; LOG4J compliant
207                    should accept a precision postfix to show the hierarchy */
208         if (precision == -1) {
209            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s",ev->cat->name);
210            check_overflow;         
211         } else {              
212            p += sprintf(p,"%.*s",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision),ev->cat->name);
213            check_overflow;         
214            precision = -1;
215         }        
216         break;
217       case 'p': /* priority name; LOG4J compliant */    
218         if (precision == -1) {
219            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", xbt_log_priority_names[ev->priority] );
220            check_overflow;         
221         } else {              
222            p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), xbt_log_priority_names[ev->priority] );
223            check_overflow;         
224            precision = -1;
225         }        
226         break;
227
228       case 'h': /* host name; SimGrid extension */
229         if (precision == -1) {
230            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", gras_os_myname());
231            check_overflow;         
232         } else {              
233            p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), gras_os_myname());
234            check_overflow;         
235            precision = -1;
236         }        
237         break;
238       case 't': /* thread name; LOG4J compliant */
239         if (precision == -1) {
240            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", xbt_thread_self_name());
241            check_overflow;         
242         } else {              
243            p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), xbt_thread_self_name());
244            check_overflow;         
245            precision = -1;
246         }        
247         break;
248       case 'P': /* process name; SimGrid extension */
249         if (precision == -1) {
250            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", xbt_procname());
251            check_overflow;         
252         } else {              
253            p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision),xbt_procname());
254            check_overflow;         
255            precision = -1;
256         }        
257         break;
258       case 'i': /* process PID name; SimGrid extension */
259         if (precision == -1) {
260            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%d", (*xbt_getpid)());
261            check_overflow;         
262         } else {              
263            p += sprintf(p, "%.*d", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), (*xbt_getpid)());
264            check_overflow;         
265            precision = -1;
266         }        
267         break;
268
269       case 'F': /* file name; LOG4J compliant */
270         if (precision == -1) {
271            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s",ev->fileName);
272            check_overflow;         
273         } else {              
274            p += sprintf(p,"%.*s",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), ev->fileName);
275            check_overflow;         
276            precision = -1;
277         }        
278         break;
279       case 'l': /* location; LOG4J compliant */
280         if (precision == -1) {
281            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s:%d", ev->fileName, ev->lineNum);
282            check_overflow;         
283         } else {              
284            p += snprintf(p, (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), "%s:%d", ev->fileName, ev->lineNum);
285            check_overflow;         
286            precision = -1;
287         }        
288         break;
289       case 'L': /* line number; LOG4J compliant */
290         if (precision == -1) {
291            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%d", ev->lineNum);
292            check_overflow;         
293         } else {              
294            p += sprintf(p, "%.*d", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), ev->lineNum);
295            check_overflow;         
296            precision = -1;
297         }        
298         break;
299       case 'M': /* method (ie, function) name; LOG4J compliant */
300         if (precision == -1) {
301            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", ev->functionName);
302            check_overflow;         
303         } else {              
304            p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), ev->functionName);
305            check_overflow;         
306            precision = -1;
307         }        
308         break;
309       case 'b': /* backtrace; called %throwable in LOG4J */
310       case 'B': /* short backtrace; called %throwable{short} in LOG4J */
311 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
312         {
313           xbt_ex_t e;
314           int i;
315           
316           e.used     = backtrace((void**)e.bt,XBT_BACKTRACE_SIZE);
317           e.bt_strings = NULL;
318           e.msg=NULL;
319           e.remote=0;
320           xbt_backtrace_current(&e);
321           if (*q=='B') {
322              if (precision == -1) {
323                p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s",e.bt_strings[2]+8);
324                check_overflow;     
325              } else {         
326                 p += sprintf(p,"%.*s",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), e.bt_strings[2]+8);
327                 check_overflow;    
328                 precision = -1;
329              }   
330           } else {
331             for (i=2; i<e.used; i++)
332                if (precision == -1) {
333                  p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s\n",e.bt_strings[i]+8);
334                  check_overflow;           
335                } else {       
336                  p += sprintf(p,"%.*s\n",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision),e.bt_strings[i]+8);
337                  check_overflow;           
338                  precision = -1;
339              }   
340           }
341            
342           xbt_ex_free(e);
343         }
344 #else
345         p+=snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"(no backtrace on this arch)");
346         check_overflow;    
347 #endif
348         break;
349
350       case 'd': /* date; LOG4J compliant */
351         if (precision == -1) {
352            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%f", gras_os_time());
353            check_overflow;         
354         } else {              
355            p += sprintf(p,"%.*f", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), gras_os_time());
356            check_overflow;         
357            precision = -1;
358         }        
359         break;
360       case 'r': /* application age; LOG4J compliant */
361         if (precision == -1) {
362            p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%f", gras_os_time()-begin_of_time);
363            check_overflow;         
364         } else {              
365            p += sprintf(p,"%.*f", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), gras_os_time()-begin_of_time);
366            check_overflow;         
367            precision = -1;
368         }        
369         break;
370         
371       case 'm': /* user-provided message; LOG4J compliant */
372         if (precision == -1) {
373            p += vsnprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), msg_fmt, ev->ap);
374            check_overflow;         
375         } else {              
376            p += vsnprintf(p, (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), msg_fmt, ev->ap);
377            check_overflow;         
378            precision = -1;
379         }        
380         break;
381
382       default:
383         fprintf(stderr,"Unknown %%%c sequence in layout format (%s)\n",
384                 *q,(char*)l->data);
385         abort();
386       }
387       q++;
388     } else {
389       *(p++) = *(q++);
390     }
391   }
392   *p = '\0';
393   app->do_append(app,ev->buffer);
394 }
395
396 static void xbt_log_layout_format_free(xbt_log_layout_t lay) {
397   free(lay->data);
398 }
399 xbt_log_layout_t xbt_log_layout_format_new(char *arg) {
400   xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t,1);
401   res->do_layout = xbt_log_layout_format_doit;
402   res->free_     = xbt_log_layout_format_free;
403   res->data = xbt_strdup((char*)arg);
404   return res;
405 }