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[7];
20 static double 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) {
54 xbt_strbuff_t buff = xbt_strbuff_new();
59 int vres; /* shut gcc up, but ignored */
67 fprintf(stderr,"Layout format (%s) ending with %%\n",(char*)l->data);
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()-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 #define check_overflow \
174 if (p-ev->buffer > XBT_LOG_BUFF_SIZE) { /* buffer overflow */ \
175 xbt_log_layout_format_dynamic(l,ev,msg_fmt,app); \
178 static void xbt_log_layout_format_doit(xbt_log_layout_t l,
181 xbt_log_appender_t app) {
186 begin_of_time=gras_os_time();
197 fprintf(stderr,"Layout format (%s) ending with %%\n",(char*)l->data);
202 case 'n': /* platform-dependant line separator (LOG4J compliant) */
203 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"\n");
206 case 'e': /* plain space (SimGrid extension) */
207 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer)," ");
211 case '.': /* precision specifyier */
213 q += sscanf(q,"%d",&precision);
214 goto handle_modifier;
216 case 'c': /* category name; LOG4J compliant
217 should accept a precision postfix to show the hierarchy */
218 if (precision == -1) {
219 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s",ev->cat->name);
222 p += sprintf(p,"%.*s",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision),ev->cat->name);
227 case 'p': /* priority name; LOG4J compliant */
228 if (precision == -1) {
229 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", xbt_log_priority_names[ev->priority] );
232 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), xbt_log_priority_names[ev->priority] );
238 case 'h': /* host name; SimGrid extension */
239 if (precision == -1) {
240 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", gras_os_myname());
243 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), gras_os_myname());
248 case 't': /* thread name; LOG4J compliant */
249 if (precision == -1) {
250 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", xbt_thread_self_name());
253 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), xbt_thread_self_name());
258 case 'P': /* process name; SimGrid extension */
259 if (precision == -1) {
260 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", xbt_procname());
263 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision),xbt_procname());
268 case 'i': /* process PID name; SimGrid extension */
269 if (precision == -1) {
270 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%d", (*xbt_getpid)());
273 p += sprintf(p, "%.*d", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), (*xbt_getpid)());
279 case 'F': /* file name; LOG4J compliant */
280 if (precision == -1) {
281 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s",ev->fileName);
284 p += sprintf(p,"%.*s",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), ev->fileName);
289 case 'l': /* location; LOG4J compliant */
290 if (precision == -1) {
291 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s:%d", ev->fileName, ev->lineNum);
294 p += snprintf(p, (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), "%s:%d", ev->fileName, ev->lineNum);
299 case 'L': /* line number; LOG4J compliant */
300 if (precision == -1) {
301 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%d", ev->lineNum);
304 p += sprintf(p, "%.*d", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), ev->lineNum);
309 case 'M': /* method (ie, function) name; LOG4J compliant */
310 if (precision == -1) {
311 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", ev->functionName);
314 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), ev->functionName);
319 case 'b': /* backtrace; called %throwable in LOG4J */
320 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
321 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
326 e.used = backtrace((void**)e.bt,XBT_BACKTRACE_SIZE);
330 xbt_backtrace_current(&e);
332 if (precision == -1) {
333 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s",e.bt_strings[2]+8);
336 p += sprintf(p,"%.*s",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), e.bt_strings[2]+8);
341 for (i=2; i<e.used; i++)
342 if (precision == -1) {
343 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s\n",e.bt_strings[i]+8);
346 p += sprintf(p,"%.*s\n",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision),e.bt_strings[i]+8);
355 p+=snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"(no backtrace on this arch)");
360 case 'd': /* date; LOG4J compliant */
361 if (precision == -1) {
362 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%f", gras_os_time());
365 p += sprintf(p,"%.*f", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), gras_os_time());
370 case 'r': /* application age; LOG4J compliant */
371 if (precision == -1) {
372 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%f", gras_os_time()-begin_of_time);
375 p += sprintf(p,"%.*f", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), gras_os_time()-begin_of_time);
381 case 'm': /* user-provided message; LOG4J compliant */
382 if (precision == -1) {
383 p += vsnprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), msg_fmt, ev->ap);
386 p += vsnprintf(p, (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), msg_fmt, ev->ap);
393 fprintf(stderr,ERRMSG,*q,(char*)l->data);
403 app->do_append(app,ev->buffer);
406 static void xbt_log_layout_format_free(xbt_log_layout_t lay) {
409 xbt_log_layout_t xbt_log_layout_format_new(char *arg) {
410 xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t,1);
411 res->do_layout = xbt_log_layout_format_doit;
412 res->free_ = xbt_log_layout_format_free;
413 res->data = xbt_strdup((char*)arg);