Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Update copyright lines.
[simgrid.git] / src / xbt / xbt_log_layout_format.cpp
1 /* layout_simple - a dumb log layout                                        */
2
3 /* Copyright (c) 2007-2021. The SimGrid Team.                               */
4
5 /* This program is free software; you can redistribute it and/or modify it
6  * under the terms of the license (GNU LGPL) which comes with this package. */
7
8 #include "simgrid/engine.h" /* simgrid_get_clock */
9 #include "simgrid/host.h"
10 #include "src/xbt/log_private.hpp"
11 #include "xbt/sysdep.h"
12 #include <algorithm>
13 #include <cstdio>
14
15 static constexpr const char* ERRMSG =
16     "Unknown %%%c sequence in layout format (%s).\n"
17     "Known sequences:\n"
18     "  what:        %%m: user message  %%c: log category  %%p: log priority\n"
19     "  where:\n"
20     "    source:    %%F: file          %%L: line          %%M: function  %%l: location (%%F:%%L)\n"
21     "    runtime:   %%h: hostname      %%t: thread        %%P: process   %%i: PID\n"
22     "  when:        %%d: date          %%r: app. age\n"
23     "  other:       %%%%: %%             %%n: new line      %%e: plain space\n";
24
25 #define check_overflow(len)                                                                                            \
26   if ((rem_size -= (len)) > 0) {                                                                                       \
27     p += (len);                                                                                                        \
28   } else                                                                                                               \
29     return false
30
31 #define set_sz_from_precision()                                                                                        \
32   if (true) {                                                                                                          \
33     sz = rem_size;                                                                                                     \
34     if (precision != -1) {                                                                                             \
35       if (precision < sz)                                                                                              \
36         sz = precision + 1; /* +1 for the final '\0' */                                                                \
37       precision = -1;                                                                                                  \
38     }                                                                                                                  \
39   } else                                                                                                               \
40     (void)0
41
42 #define show_it(data, letter)                                                                                          \
43   if (true) {                                                                                                          \
44     int len;                                                                                                           \
45     int wd;                                                                                                            \
46     if (length == -1) {                                                                                                \
47       wd = 0;                                                                                                          \
48     } else {                                                                                                           \
49       wd     = length;                                                                                                 \
50       length = -1;                                                                                                     \
51     }                                                                                                                  \
52     if (precision == -1) {                                                                                             \
53       len = snprintf(p, rem_size, "%*" letter, wd, (data));                                                            \
54     } else {                                                                                                           \
55       len       = snprintf(p, rem_size, "%*.*" letter, wd, precision, (data));                                         \
56       precision = -1;                                                                                                  \
57     }                                                                                                                  \
58     check_overflow(len);                                                                                               \
59   } else                                                                                                               \
60     (void)0
61
62 #define show_string(data)                                                                                              \
63   if (true) {                                                                                                          \
64     const char* show_string_data = (data);                                                                             \
65     show_it(show_string_data ? show_string_data : "(null)", "s");                                                      \
66   } else                                                                                                               \
67     (void)0
68 #define show_int(data) show_it((data), "d")
69 #define show_double(data) show_it((data), "f")
70
71 static bool xbt_log_layout_format_doit(const s_xbt_log_layout_t* l, xbt_log_event_t ev, const char* msg_fmt)
72 {
73   char *p = ev->buffer;
74   int rem_size = ev->buffer_size;
75   int precision = -1;
76   int length = -1;
77
78   auto* q = static_cast<char*>(l->data);
79   while (*q != '\0') {
80     if (*q != '%') {
81       *p = *q;
82       check_overflow(1);
83       q++;
84       continue;
85     }
86
87     // *q == '%'
88     q++;
89     do {
90       switch (*q) {
91         case '\0':
92           fprintf(stderr, "Layout format (%s) ending with %%\n", (char*)l->data);
93           xbt_abort();
94         case '%':
95           *p = '%';
96           check_overflow(1);
97           break;
98         case 'n': /* platform-dependant line separator; LOG4J compliant */
99           *p = '\n';
100           check_overflow(1);
101           break;
102         case 'e': /* plain space; SimGrid extension */
103           *p = ' ';
104           check_overflow(1);
105           break;
106         case '.': /* precision specifier */
107           precision = static_cast<int>(strtol(q + 1, &q, 10));
108           continue; /* conversion specifier still not found, continue reading */
109         case '0':
110         case '1':
111         case '2':
112         case '3':
113         case '4':
114         case '5':
115         case '6':
116         case '7':
117         case '8':
118         case '9': /* length modifier */
119           length = static_cast<int>(strtol(q, &q, 10));
120           continue; /* conversion specifier still not found, continue reading */
121         case 'c':   /* category name; LOG4J compliant
122                        should accept a precision postfix to show the hierarchy */
123           show_string(ev->cat->name);
124           break;
125         case 'p': /* priority name; LOG4J compliant */
126           show_string(xbt_log_priority_names[ev->priority]);
127           break;
128         case 'h': /* host name; SimGrid extension */
129           show_string(sg_host_self_get_name());
130           break;
131         case 't': /* thread/process name; LOG4J compliant */
132         case 'P': /* process name; SimGrid extension */
133           show_string(xbt_procname());
134           break;
135         case 'i': /* process PID name; SimGrid extension */
136           show_int(xbt_getpid());
137           break;
138         case 'F': /* file name; LOG4J compliant */
139           show_string(ev->fileName);
140           break;
141         case 'l': { /* location; LOG4J compliant */
142           int sz;
143           set_sz_from_precision();
144           int len = snprintf(p, sz, "%s:%d", ev->fileName, ev->lineNum);
145           check_overflow(std::min(sz, len));
146           break;
147         }
148         case 'L': /* line number; LOG4J compliant */
149           show_int(ev->lineNum);
150           break;
151         case 'M': /* method (ie, function) name; LOG4J compliant */
152           show_string(ev->functionName);
153           break;
154         case 'd': /* date; LOG4J compliant */
155         case 'r': /* application age; LOG4J compliant */
156           show_double(simgrid_get_clock());
157           break;
158         case 'm': { /* user-provided message; LOG4J compliant */
159           int sz;
160           set_sz_from_precision();
161           va_list ap;
162           va_copy(ap, ev->ap);
163           int len = vsnprintf(p, sz, msg_fmt, ap);
164           va_end(ap);
165           check_overflow(std::min(sz, len));
166           break;
167         }
168         default:
169           fprintf(stderr, ERRMSG, *q, (char*)l->data);
170           xbt_abort();
171       }
172       break; /* done, continue normally */
173     } while (true);
174     q++;
175   }
176   *p = '\0';
177
178   return true;
179 }
180
181 static void xbt_log_layout_format_free(const s_xbt_log_layout_t* lay)
182 {
183   xbt_free(lay->data);
184 }
185
186 xbt_log_layout_t xbt_log_layout_format_new(const char* arg)
187 {
188   xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t, 1);
189   res->do_layout       = &xbt_log_layout_format_doit;
190   res->free_           = &xbt_log_layout_format_free;
191   res->data            = xbt_strdup(arg);
192
193   return res;
194 }