Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
cleanups
[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      %%a: actor         %%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       int sz;
91       int len;
92       switch (*q) {
93         case '\0':
94           fprintf(stderr, "Layout format (%s) ending with %%\n", (char*)l->data);
95           xbt_abort();
96         case '%':
97           *p = '%';
98           check_overflow(1);
99           break;
100         case 'n': /* platform-dependant line separator; LOG4J compliant */
101           *p = '\n';
102           check_overflow(1);
103           break;
104         case 'e': /* plain space; SimGrid extension */
105           *p = ' ';
106           check_overflow(1);
107           break;
108         case '.': /* precision specifier */
109           precision = static_cast<int>(strtol(q + 1, &q, 10));
110           continue; /* conversion specifier still not found, continue reading */
111         case '0':
112         case '1':
113         case '2':
114         case '3':
115         case '4':
116         case '5':
117         case '6':
118         case '7':
119         case '8':
120         case '9': /* length modifier */
121           length = static_cast<int>(strtol(q, &q, 10));
122           continue; /* conversion specifier still not found, continue reading */
123         case 'c':   /* category name; LOG4J compliant
124                        should accept a precision postfix to show the hierarchy */
125           show_string(ev->cat->name);
126           break;
127         case 'p': /* priority name; LOG4J compliant */
128           show_string(xbt_log_priority_names[ev->priority]);
129           break;
130         case 'h': /* host name; SimGrid extension */
131           show_string(sg_host_self_get_name());
132           break;
133         case 't': /* thread/process name; LOG4J compliant */
134         case 'P': /* Used before SimGrid 3.26 and kept for compatiblity. Should not hurt. */
135         case 'a': /* actor name; SimGrid extension */
136           show_string(xbt_procname());
137           break;
138         case 'i': /* actor ID; SimGrid extension */
139           show_int(xbt_getpid());
140           break;
141         case 'F': /* file name; LOG4J compliant */
142           show_string(ev->fileName);
143           break;
144         case 'l': /* location; LOG4J compliant */
145           set_sz_from_precision();
146           len = snprintf(p, sz, "%s:%d", ev->fileName, ev->lineNum);
147           check_overflow(std::min(sz, len));
148           break;
149         case 'L': /* line number; LOG4J compliant */
150           show_int(ev->lineNum);
151           break;
152         case 'M': /* method (ie, function) name; LOG4J compliant */
153           show_string(ev->functionName);
154           break;
155         case 'd': /* date; LOG4J compliant */
156         case 'r': /* application age; LOG4J compliant */
157           show_double(simgrid_get_clock());
158           break;
159         case 'm': /* user-provided message; LOG4J compliant */
160           set_sz_from_precision();
161           va_list ap;
162           va_copy(ap, ev->ap);
163           len = vsnprintf(p, sz, msg_fmt, ap);
164           va_end(ap);
165           check_overflow(std::min(sz, len));
166           break;
167         default:
168           fprintf(stderr, ERRMSG, *q, (char*)l->data);
169           xbt_abort();
170       }
171       break; /* done, continue normally */
172     } while (true);
173     q++;
174   }
175   *p = '\0';
176
177   return true;
178 }
179
180 static void xbt_log_layout_format_free(const s_xbt_log_layout_t* lay)
181 {
182   xbt_free(lay->data);
183 }
184
185 xbt_log_layout_t xbt_log_layout_format_new(const char* arg)
186 {
187   xbt_log_layout_t res = xbt_new0(s_xbt_log_layout_t, 1);
188   res->do_layout       = &xbt_log_layout_format_doit;
189   res->free_           = &xbt_log_layout_format_free;
190   res->data            = xbt_strdup(arg);
191
192   return res;
193 }