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();
66 fprintf(stderr,"Layout format (%s) ending with %%\n",(char*)l->data);
69 xbt_strbuff_append(buff,"%");
71 case 'n': /* platform-dependant line separator (LOG4J compliant) */
72 xbt_strbuff_append(buff,"\n");
74 case 'e': /* plain space (SimGrid extension) */
75 xbt_strbuff_append(buff," ");
78 case '.': /* precision specifyier */
80 q += sscanf(q,"%d",&precision);
83 case 'c': /* category name; LOG4J compliant
84 should accept a precision postfix to show the hierarchy */
85 append1("%s","%.*s",ev->cat->name);
87 case 'p': /* priority name; LOG4J compliant */
88 append1("%s","%.*s",xbt_log_priority_names[ev->priority]);
91 case 'h': /* host name; SimGrid extension */
92 append1("%s","%.*s",gras_os_myname());
94 case 't': /* thread name; LOG4J compliant */
95 append1("%s","%.*s",xbt_thread_self_name());
97 case 'P': /* process name; SimGrid extension */
98 append1("%s","%.*s",xbt_procname());
100 case 'i': /* process PID name; SimGrid extension */
101 append1("%d","%.*d",(*xbt_getpid)());
104 case 'F': /* file name; LOG4J compliant */
105 append1("%s","%.*s",ev->fileName);
107 case 'l': /* location; LOG4J compliant */
108 append2("%s:%d",ev->fileName,ev->lineNum);
109 precision = -1; /* Ignored */
111 case 'L': /* line number; LOG4J compliant */
112 append1("%d","%.*d",ev->lineNum);
114 case 'M': /* method (ie, function) name; LOG4J compliant */
115 append1("%s","%.*s",ev->functionName);
117 case 'b': /* backtrace; called %throwable in LOG4J */
118 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
119 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
124 e.used = backtrace((void**)e.bt,XBT_BACKTRACE_SIZE);
128 xbt_backtrace_current(&e);
130 append1("%s","%.*s",e.bt_strings[2]+8);
132 for (i=2; i<e.used; i++)
133 append1("%s\n","%.*s\n",e.bt_strings[i]+8);
139 append1("%s","%.*s","(no backtrace on this arch)");
143 case 'd': /* date; LOG4J compliant */
144 append1("%f","%.*f", gras_os_time());
146 case 'r': /* application age; LOG4J compliant */
147 append1("%f","%.*f", gras_os_time()-begin_of_time);
150 case 'm': /* user-provided message; LOG4J compliant */
151 vasprintf(&tmp2, fmt, ev->ap_copy);
152 append1("%s","%.*s",tmp2);
157 fprintf(stderr,ERRMSG, *q,(char*)l->data);
165 xbt_strbuff_append(buff,tmp2);
168 app->do_append(app,buff->data);
169 xbt_strbuff_free(buff);
172 #define check_overflow \
173 if (p-ev->buffer > XBT_LOG_BUFF_SIZE) { /* buffer overflow */ \
174 xbt_log_layout_format_dynamic(l,ev,msg_fmt,app); \
177 static void xbt_log_layout_format_doit(xbt_log_layout_t l,
180 xbt_log_appender_t app) {
185 begin_of_time=gras_os_time();
196 fprintf(stderr,"Layout format (%s) ending with %%\n",(char*)l->data);
201 case 'n': /* platform-dependant line separator (LOG4J compliant) */
202 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"\n");
205 case 'e': /* plain space (SimGrid extension) */
206 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer)," ");
210 case '.': /* precision specifyier */
212 q += sscanf(q,"%d",&precision);
213 goto handle_modifier;
215 case 'c': /* category name; LOG4J compliant
216 should accept a precision postfix to show the hierarchy */
217 if (precision == -1) {
218 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s",ev->cat->name);
221 p += sprintf(p,"%.*s",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision),ev->cat->name);
226 case 'p': /* priority name; LOG4J compliant */
227 if (precision == -1) {
228 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", xbt_log_priority_names[ev->priority] );
231 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), xbt_log_priority_names[ev->priority] );
237 case 'h': /* host name; SimGrid extension */
238 if (precision == -1) {
239 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", gras_os_myname());
242 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), gras_os_myname());
247 case 't': /* thread name; LOG4J compliant */
248 if (precision == -1) {
249 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", xbt_thread_self_name());
252 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), xbt_thread_self_name());
257 case 'P': /* process name; SimGrid extension */
258 if (precision == -1) {
259 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", xbt_procname());
262 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision),xbt_procname());
267 case 'i': /* process PID name; SimGrid extension */
268 if (precision == -1) {
269 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%d", (*xbt_getpid)());
272 p += sprintf(p, "%.*d", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), (*xbt_getpid)());
278 case 'F': /* file name; LOG4J compliant */
279 if (precision == -1) {
280 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s",ev->fileName);
283 p += sprintf(p,"%.*s",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), ev->fileName);
288 case 'l': /* location; LOG4J compliant */
289 if (precision == -1) {
290 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s:%d", ev->fileName, ev->lineNum);
293 p += snprintf(p, (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), "%s:%d", ev->fileName, ev->lineNum);
298 case 'L': /* line number; LOG4J compliant */
299 if (precision == -1) {
300 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%d", ev->lineNum);
303 p += sprintf(p, "%.*d", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), ev->lineNum);
308 case 'M': /* method (ie, function) name; LOG4J compliant */
309 if (precision == -1) {
310 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), "%s", ev->functionName);
313 p += sprintf(p, "%.*s", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), ev->functionName);
318 case 'b': /* backtrace; called %throwable in LOG4J */
319 case 'B': /* short backtrace; called %throwable{short} in LOG4J */
320 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
325 e.used = backtrace((void**)e.bt,XBT_BACKTRACE_SIZE);
329 xbt_backtrace_current(&e);
331 if (precision == -1) {
332 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s",e.bt_strings[2]+8);
335 p += sprintf(p,"%.*s",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), e.bt_strings[2]+8);
340 for (i=2; i<e.used; i++)
341 if (precision == -1) {
342 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%s\n",e.bt_strings[i]+8);
345 p += sprintf(p,"%.*s\n",(int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision),e.bt_strings[i]+8);
354 p+=snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"(no backtrace on this arch)");
359 case 'd': /* date; LOG4J compliant */
360 if (precision == -1) {
361 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%f", gras_os_time());
364 p += sprintf(p,"%.*f", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), gras_os_time());
369 case 'r': /* application age; LOG4J compliant */
370 if (precision == -1) {
371 p += snprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer),"%f", gras_os_time()-begin_of_time);
374 p += sprintf(p,"%.*f", (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), gras_os_time()-begin_of_time);
380 case 'm': /* user-provided message; LOG4J compliant */
381 if (precision == -1) {
382 p += vsnprintf(p,XBT_LOG_BUFF_SIZE-(p-ev->buffer), msg_fmt, ev->ap);
385 p += vsnprintf(p, (int)MIN(XBT_LOG_BUFF_SIZE-(p-ev->buffer),precision), msg_fmt, ev->ap);
392 fprintf(stderr,ERRMSG,*q,(char*)l->data);
402 app->do_append(app,ev->buffer);
405 static void xbt_log_layout_format_free(xbt_log_layout_t lay) {
408 xbt_log_layout_t xbt_log_layout_format_new(char *arg) {
409 xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t,1);
410 res->do_layout = xbt_log_layout_format_doit;
411 res->free_ = xbt_log_layout_format_free;
412 res->data = xbt_strdup((char*)arg);