cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / logging / log-api.h
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (c) 2016 wonder-mice
5 * Copyright (c) 2016-2023 Philippe Proulx <pproulx@efficios.com>
6 *
7 * This is very inspired by zf_log.h (see
8 * <https://github.com/wonder-mice/zf_log/>), but modified (mostly
9 * stripped down) for the use cases of Babeltrace.
10 */
11
12 #ifndef BABELTRACE_LOGGING_LOG_API_H
13 #define BABELTRACE_LOGGING_LOG_API_H
14
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <glib.h>
20 #include <babeltrace2/babeltrace.h>
21
22 /* Access private `__BT_LOGGING_LEVEL_*` macros. */
23 #define __BT_IN_BABELTRACE_H
24 #include <babeltrace2/logging-defs.h>
25 #undef __BT_IN_BABELTRACE_H
26
27 #include "common/macros.h"
28 #include "common/assert.h"
29
30 /* Log levels */
31 enum bt_log_level {
32 BT_LOG_TRACE = __BT_LOGGING_LEVEL_TRACE,
33 BT_LOG_DEBUG = __BT_LOGGING_LEVEL_DEBUG,
34 BT_LOG_INFO = __BT_LOGGING_LEVEL_INFO,
35 BT_LOG_WARNING = __BT_LOGGING_LEVEL_WARNING,
36 BT_LOG_ERROR = __BT_LOGGING_LEVEL_ERROR,
37 BT_LOG_FATAL = __BT_LOGGING_LEVEL_FATAL,
38 BT_LOG_NONE = __BT_LOGGING_LEVEL_NONE,
39 };
40
41 /*
42 * `BT_LOG_MINIMAL_LEVEL` (constant integer, mandatory): minimal log
43 * level to completely disable (not build) logging with levels that are
44 * more verbose.
45 */
46 #ifndef BT_LOG_MINIMAL_LEVEL
47 # error "`BT_LOG_MINIMAL_LEVEL` must to defined"
48 #endif
49
50 /* Internal: portable printf()-like attribute */
51 #if defined(__printflike)
52 # define _BT_LOG_PRINTFLIKE(_str_index, _first_to_check) \
53 __printflike(_str_index, _first_to_check)
54 #elif defined(__MINGW_PRINTF_FORMAT)
55 # define _BT_LOG_PRINTFLIKE(_str_index, _first_to_check) \
56 __attribute__((format(__MINGW_PRINTF_FORMAT, _str_index, _first_to_check)))
57 #elif defined(__GNUC__)
58 # define _BT_LOG_PRINTFLIKE(_str_index, _first_to_check) \
59 __attribute__((format(__printf__, _str_index, _first_to_check)))
60 #else
61 # define _BT_LOG_PRINTFLIKE(_str_index, _first_to_check)
62 #endif
63
64 /*
65 * Runs `_expr` if `_cond` is true.
66 */
67 #define BT_LOG_IF(_cond, _expr) do { if (_cond) { _expr; } } while (0)
68
69 /*
70 * Returns whether or not `_lvl` is enabled at build time, that is, it's
71 * equally or less verbose than `BT_LOG_MINIMAL_LEVEL`.
72 *
73 * See `BT_LOG_MINIMAL_LEVEL` to learn more.
74 */
75 #define BT_LOG_ENABLED(_lvl) ((_lvl) >= BT_LOG_MINIMAL_LEVEL)
76 #define BT_LOG_ENABLED_TRACE BT_LOG_ENABLED(__BT_LOGGING_LEVEL_TRACE)
77 #define BT_LOG_ENABLED_DEBUG BT_LOG_ENABLED(__BT_LOGGING_LEVEL_DEBUG)
78 #define BT_LOG_ENABLED_INFO BT_LOG_ENABLED(__BT_LOGGING_LEVEL_INFO)
79 #define BT_LOG_ENABLED_WARNING BT_LOG_ENABLED(__BT_LOGGING_LEVEL_WARNING)
80 #define BT_LOG_ENABLED_ERROR BT_LOG_ENABLED(__BT_LOGGING_LEVEL_ERROR)
81 #define BT_LOG_ENABLED_FATAL BT_LOG_ENABLED(__BT_LOGGING_LEVEL_FATAL)
82
83 /*
84 * Returns whether or not `_lvl` is enabled at run time, that is, it's
85 * equally or less verbose than some current (run-time) level
86 * `_cur_lvl`.
87 */
88 #define BT_LOG_ON_CUR_LVL(_lvl, _cur_lvl) \
89 G_UNLIKELY(BT_LOG_ENABLED((_lvl)) && (_lvl) >= (_cur_lvl))
90
91 #ifdef __cplusplus
92 extern "C" {
93 #endif
94
95 /*
96 * Writes the log message `msg` using the file name `file_name`, the
97 * function name `func_name`, the line number `line_no`, the log level
98 * `lvl`, and the tag `tag`.
99 *
100 * NOTE: This function writes unconditionally, without checking the
101 * current (run-time) log level.
102 */
103 void bt_log_write(const char *file_name, const char *func_name,
104 unsigned int line_no, enum bt_log_level lvl, const char *tag,
105 const char *msg);
106
107 /*
108 * Calls bt_log_write(), formatting the log message through sprintf()
109 * with `fmt` and the following arguments.
110 */
111 void bt_log_write_printf(const char *file_name, const char *func_name,
112 unsigned int line_no, enum bt_log_level lvl, const char *tag,
113 const char *fmt, ...) _BT_LOG_PRINTFLIKE(6, 7);
114
115 /*
116 * Writes the log message `msg` using the file name `file_name`, the
117 * function name `func_name`, the line number `line_no`, the log level
118 * `lvl`, and the tag `tag`, and also dumps `mem_len` bytes of
119 * `mem_data`.
120 *
121 * NOTE: This function writes unconditionally, without checking the
122 * current (run-time) log level.
123 */
124 void bt_log_write_mem(const char *file_name, const char *func_name,
125 unsigned int line_no, enum bt_log_level lvl, const char *tag,
126 const void *mem_data, size_t mem_len,
127 const char *msg);
128
129 /*
130 * Calls bt_log_write_mem(), formatting the log message through
131 * sprintf() with `fmt` and the following arguments.
132 */
133 void bt_log_write_mem_printf(const char *file_name, const char *func_name,
134 unsigned int line_no, enum bt_log_level lvl, const char *tag,
135 const void *mem_data, size_t mem_len,
136 const char *fmt, ...) _BT_LOG_PRINTFLIKE(8, 9);
137
138 /*
139 * Writes:
140 *
141 * 1. `init_msg`
142 * 2. The string `: `
143 * 3. The message corresponding to `errno` (current error number)
144 * 4. `msg`
145 *
146 * This function uses the file name `file_name`, the function name
147 * `func_name`, the line number `line_no`, the log level `lvl`, and the
148 * tag `tag`.
149 *
150 * NOTE: This function writes unconditionally, without checking the
151 * current (run-time) log level.
152 */
153 void bt_log_write_errno(const char *file_name, const char *func_name,
154 unsigned int line_no, enum bt_log_level lvl, const char *tag,
155 const char *init_msg, const char *msg);
156
157 /*
158 * Calls bt_log_write_errno(), formatting the log message through
159 * sprintf() with `fmt` and the following arguments.
160 */
161 void bt_log_write_errno_printf(const char *file_name, const char *func_name,
162 unsigned int line_no, enum bt_log_level lvl, const char *tag,
163 const char *init_msg,
164 const char *fmt, ...) _BT_LOG_PRINTFLIKE(7, 8);
165
166 #ifdef __cplusplus
167 }
168 #endif
169
170 /*
171 * Calls bt_log_write() if logging is enabled at run time for the
172 * current level `_cur_lvl`.
173 *
174 * Passes the current file name, function name, and line number to
175 * bt_log_write().
176 */
177 #define BT_LOG_WRITE_CUR_LVL(_lvl, _cur_lvl, _tag, _msg) \
178 do { \
179 if (BT_LOG_ON_CUR_LVL((_lvl), (_cur_lvl))) { \
180 bt_log_write(__FILE__, __func__, __LINE__, \
181 (_lvl), (_tag), (_msg)); \
182 } \
183 } while (0)
184
185 /*
186 * Calls bt_log_write_printf() if logging is enabled at run time for the
187 * current level `_cur_lvl`.
188 *
189 * Passes the current file name, function name, and line number to
190 * bt_log_write_printf().
191 */
192 #define BT_LOG_WRITE_PRINTF_CUR_LVL(_lvl, _cur_lvl, _tag, _fmt, ...) \
193 do { \
194 if (BT_LOG_ON_CUR_LVL((_lvl), (_cur_lvl))) { \
195 bt_log_write_printf(__FILE__, __func__, \
196 __LINE__, (_lvl), (_tag), (_fmt), \
197 ##__VA_ARGS__); \
198 } \
199 } while (0)
200
201 /*
202 * Calls bt_log_write_mem() if logging is enabled at run time for the
203 * current level `_cur_lvl`.
204 *
205 * Passes the current file name, function name, and line number to
206 * bt_log_write_mem().
207 */
208 #define BT_LOG_WRITE_MEM_CUR_LVL(_lvl, _cur_lvl, _tag, _mem_data, _mem_len, _msg) \
209 do { \
210 if (BT_LOG_ON_CUR_LVL((_lvl), (_cur_lvl))) { \
211 bt_log_write_mem(__FILE__, __func__, __LINE__, \
212 (_lvl), (_tag), (_mem_data), \
213 (_mem_len), (_msg)); \
214 } \
215 } while (0)
216
217 /*
218 * Calls bt_log_write_mem_printf() if logging is enabled at run time for
219 * the current level `_cur_lvl`.
220 *
221 * Passes the current file name, function name, and line number to
222 * bt_log_write_mem_printf().
223 */
224 #define BT_LOG_WRITE_MEM_PRINTF_CUR_LVL(_lvl, _cur_lvl, _tag, _mem_data, _mem_len, _fmt, ...) \
225 do { \
226 if (BT_LOG_ON_CUR_LVL((_lvl), (_cur_lvl))) { \
227 bt_log_write_mem_printf(__FILE__, __func__, \
228 __LINE__, (_lvl), (_tag), (_mem_data), \
229 (_mem_len), (_fmt), ##__VA_ARGS__); \
230 } \
231 } while (0)
232
233 /*
234 * Calls bt_log_write_errno() if logging is enabled at run time for the
235 * current level `_cur_lvl`.
236 *
237 * Passes the current file name, function name, and line number to
238 * bt_log_write_errno().
239 */
240 #define BT_LOG_WRITE_ERRNO_CUR_LVL(_lvl, _cur_lvl, _tag, _init_msg, _msg) \
241 do { \
242 if (BT_LOG_ON_CUR_LVL((_lvl), (_cur_lvl))) { \
243 bt_log_write_errno(__FILE__, __func__, \
244 __LINE__, (_lvl), (_tag), (_init_msg), \
245 (_msg)); \
246 } \
247 } while (0)
248
249 /*
250 * Calls bt_log_write_errno_printf() if logging is enabled at run time
251 * for the current level `_cur_lvl`.
252 *
253 * Passes the current file name, function name, and line number to
254 * bt_log_write_errno_printf().
255 */
256 #define BT_LOG_WRITE_ERRNO_PRINTF_CUR_LVL(_lvl, _cur_lvl, _tag, _init_msg, _fmt, ...) \
257 do { \
258 if (BT_LOG_ON_CUR_LVL((_lvl), (_cur_lvl))) { \
259 bt_log_write_errno_printf(__FILE__, __func__, \
260 __LINE__, (_lvl), (_tag), (_init_msg), \
261 (_fmt), ##__VA_ARGS__); \
262 } \
263 } while (0)
264
265 /*
266 * Returns the equivalent letter of the log level `level`.
267 *
268 * `level` must be a valid log level.
269 */
270 static inline
271 char bt_log_get_letter_from_level(const enum bt_log_level level)
272 {
273 char letter;
274
275 switch (level) {
276 case BT_LOG_TRACE:
277 letter = 'T';
278 break;
279 case BT_LOG_DEBUG:
280 letter = 'D';
281 break;
282 case BT_LOG_INFO:
283 letter = 'I';
284 break;
285 case BT_LOG_WARNING:
286 letter = 'W';
287 break;
288 case BT_LOG_ERROR:
289 letter = 'E';
290 break;
291 case BT_LOG_FATAL:
292 letter = 'F';
293 break;
294 case BT_LOG_NONE:
295 letter = 'N';
296 break;
297 default:
298 abort();
299 }
300
301 return letter;
302 }
303
304 /*
305 * Returns the log level as an integer for the string `str`, or -1 if
306 * `str` is not a valid log level string.
307 */
308 static inline
309 int bt_log_get_level_from_string(const char * const str)
310 {
311 int level = -1;
312
313 BT_ASSERT(str);
314
315 if (strcmp(str, "TRACE") == 0 || strcmp(str, "T") == 0) {
316 level = BT_LOG_TRACE;
317 } else if (strcmp(str, "DEBUG") == 0 || strcmp(str, "D") == 0) {
318 level = BT_LOG_DEBUG;
319 } else if (strcmp(str, "INFO") == 0 || strcmp(str, "I") == 0) {
320 level = BT_LOG_INFO;
321 } else if (strcmp(str, "WARN") == 0 ||
322 strcmp(str, "WARNING") == 0 ||
323 strcmp(str, "W") == 0) {
324 level = BT_LOG_WARNING;
325 } else if (strcmp(str, "ERROR") == 0 || strcmp(str, "E") == 0) {
326 level = BT_LOG_ERROR;
327 } else if (strcmp(str, "FATAL") == 0 || strcmp(str, "F") == 0) {
328 level = BT_LOG_FATAL;
329 } else if (strcmp(str, "NONE") == 0 || strcmp(str, "N") == 0) {
330 level = BT_LOG_NONE;
331 } else {
332 /* FIXME: Should we warn here? How? */
333 }
334
335 return level;
336 }
337
338 /*
339 * Returns the log level as an integer for the letter `letter`, or -1 if
340 * `letter` is not a valid log level string.
341 */
342 static inline
343 int bt_log_get_level_from_letter(const char letter)
344 {
345 const char str[] = {letter, '\0'};
346
347 return bt_log_get_level_from_string(str);
348 }
349
350 /*
351 * Returns the log level for the value of the environment variable named
352 * `env_var_name`, or `BT_LOG_NONE` if not a valid log level string.
353 */
354 static inline
355 enum bt_log_level bt_log_get_level_from_env(const char *env_var_name)
356 {
357 const char * const varval = getenv(env_var_name);
358 enum bt_log_level level = BT_LOG_NONE;
359 int int_level;
360
361 if (!varval) {
362 goto end;
363 }
364
365 int_level = bt_log_get_level_from_string(varval);
366 if (int_level < 0) {
367 /* FIXME: Should we warn here? How? */
368 int_level = BT_LOG_NONE;
369 }
370
371 level = (enum bt_log_level) int_level;
372
373 end:
374 return level;
375 }
376
377 /*
378 * Declares the variable named `_level_sym` as an external symbol
379 * containing a log level.
380 */
381 #define BT_LOG_LEVEL_EXTERN_SYMBOL(_level_sym) \
382 extern enum bt_log_level _level_sym
383
384 /*
385 * 1. Defines the log level variable `_level_sym`, initializing it to
386 * `BT_LOG_NONE` (logging disabled).
387 *
388 * 2. Defines a library constructor named _bt_log_level_ctor() which
389 * initializes the log level variable `_level_sym` from the value of
390 * the environment variable named `_env_var_name`.
391 */
392 #define BT_LOG_INIT_LOG_LEVEL(_level_sym, _env_var_name) \
393 enum bt_log_level _level_sym = BT_LOG_NONE; \
394 static \
395 void __attribute__((constructor)) _bt_log_level_ctor(void) \
396 { \
397 _level_sym = bt_log_get_level_from_env(_env_var_name); \
398 }
399
400 #endif /* BABELTRACE_LOGGING_LOG_API_H */
This page took 0.039916 seconds and 4 git commands to generate.