Logo AND Algorithmique Numérique Distribuée

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