2 * SPDX-License-Identifier: MIT
4 * Copyright (c) 2016 wonder-mice
5 * Copyright (c) 2016-2023 Philippe Proulx <pproulx@efficios.com>
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.
12 #ifndef BABELTRACE_LOGGING_LOG_API_H
13 #define BABELTRACE_LOGGING_LOG_API_H
20 #include <babeltrace2/babeltrace.h>
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
27 #include "common/macros.h"
28 #include "common/assert.h"
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
,
42 * `BT_LOG_MINIMAL_LEVEL` (constant integer, mandatory): minimal log
43 * level to completely disable (not build) logging with levels that are
46 #ifndef BT_LOG_MINIMAL_LEVEL
47 # error "`BT_LOG_MINIMAL_LEVEL` must to defined"
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)))
61 # define _BT_LOG_PRINTFLIKE(_str_index, _first_to_check)
65 * Runs `_expr` if `_cond` is true.
67 #define BT_LOG_IF(_cond, _expr) do { if (_cond) { _expr; } } while (0)
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`.
73 * See `BT_LOG_MINIMAL_LEVEL` to learn more.
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)
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
88 #define BT_LOG_ON_CUR_LVL(_lvl, _cur_lvl) \
89 G_UNLIKELY(BT_LOG_ENABLED((_lvl)) && (_lvl) >= (_cur_lvl))
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`.
100 * NOTE: This function writes unconditionally, without checking the
101 * current (run-time) log level.
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
,
108 * Calls bt_log_write(), formatting the log message through sprintf()
109 * with `fmt` and the following arguments.
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);
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
121 * NOTE: This function writes unconditionally, without checking the
122 * current (run-time) log level.
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
,
130 * Calls bt_log_write_mem(), formatting the log message through
131 * sprintf() with `fmt` and the following arguments.
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);
143 * 3. The message corresponding to `errno` (current error number)
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
150 * NOTE: This function writes unconditionally, without checking the
151 * current (run-time) log level.
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
);
158 * Calls bt_log_write_errno(), formatting the log message through
159 * sprintf() with `fmt` and the following arguments.
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);
171 * Calls bt_log_write() if logging is enabled at run time for the
172 * current level `_cur_lvl`.
174 * Passes the current file name, function name, and line number to
177 #define BT_LOG_WRITE_CUR_LVL(_lvl, _cur_lvl, _tag, _msg) \
179 if (BT_LOG_ON_CUR_LVL((_lvl), (_cur_lvl))) { \
180 bt_log_write(__FILE__, __func__, __LINE__, \
181 (_lvl), (_tag), (_msg)); \
186 * Calls bt_log_write_printf() if logging is enabled at run time for the
187 * current level `_cur_lvl`.
189 * Passes the current file name, function name, and line number to
190 * bt_log_write_printf().
192 #define BT_LOG_WRITE_PRINTF_CUR_LVL(_lvl, _cur_lvl, _tag, _fmt, ...) \
194 if (BT_LOG_ON_CUR_LVL((_lvl), (_cur_lvl))) { \
195 bt_log_write_printf(__FILE__, __func__, \
196 __LINE__, (_lvl), (_tag), (_fmt), \
202 * Calls bt_log_write_mem() if logging is enabled at run time for the
203 * current level `_cur_lvl`.
205 * Passes the current file name, function name, and line number to
206 * bt_log_write_mem().
208 #define BT_LOG_WRITE_MEM_CUR_LVL(_lvl, _cur_lvl, _tag, _mem_data, _mem_len, _msg) \
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)); \
218 * Calls bt_log_write_mem_printf() if logging is enabled at run time for
219 * the current level `_cur_lvl`.
221 * Passes the current file name, function name, and line number to
222 * bt_log_write_mem_printf().
224 #define BT_LOG_WRITE_MEM_PRINTF_CUR_LVL(_lvl, _cur_lvl, _tag, _mem_data, _mem_len, _fmt, ...) \
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__); \
234 * Calls bt_log_write_errno() if logging is enabled at run time for the
235 * current level `_cur_lvl`.
237 * Passes the current file name, function name, and line number to
238 * bt_log_write_errno().
240 #define BT_LOG_WRITE_ERRNO_CUR_LVL(_lvl, _cur_lvl, _tag, _init_msg, _msg) \
242 if (BT_LOG_ON_CUR_LVL((_lvl), (_cur_lvl))) { \
243 bt_log_write_errno(__FILE__, __func__, \
244 __LINE__, (_lvl), (_tag), (_init_msg), \
250 * Calls bt_log_write_errno_printf() if logging is enabled at run time
251 * for the current level `_cur_lvl`.
253 * Passes the current file name, function name, and line number to
254 * bt_log_write_errno_printf().
256 #define BT_LOG_WRITE_ERRNO_PRINTF_CUR_LVL(_lvl, _cur_lvl, _tag, _init_msg, _fmt, ...) \
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__); \
266 * Returns the equivalent letter of the log level `level`.
268 * `level` must be a valid log level.
271 char bt_log_get_letter_from_level(const enum bt_log_level level
)
305 * Returns the log level as an integer for the string `str`, or -1 if
306 * `str` is not a valid log level string.
309 int bt_log_get_level_from_string(const char * const str
)
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) {
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) {
332 /* FIXME: Should we warn here? How? */
339 * Returns the log level as an integer for the letter `letter`, or -1 if
340 * `letter` is not a valid log level string.
343 int bt_log_get_level_from_letter(const char letter
)
345 const char str
[] = {letter
, '\0'};
347 return bt_log_get_level_from_string(str
);
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.
355 enum bt_log_level
bt_log_get_level_from_env(const char *env_var_name
)
357 const char * const varval
= getenv(env_var_name
);
358 enum bt_log_level level
= BT_LOG_NONE
;
365 int_level
= bt_log_get_level_from_string(varval
);
367 /* FIXME: Should we warn here? How? */
368 int_level
= BT_LOG_NONE
;
371 level
= (enum bt_log_level
) int_level
;
378 * Declares the variable named `_level_sym` as an external symbol
379 * containing a log level.
381 #define BT_LOG_LEVEL_EXTERN_SYMBOL(_level_sym) \
382 extern enum bt_log_level _level_sym
385 * 1. Defines the log level variable `_level_sym`, initializing it to
386 * `BT_LOG_NONE` (logging disabled).
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`.
392 #define BT_LOG_INIT_LOG_LEVEL(_level_sym, _env_var_name) \
393 enum bt_log_level _level_sym = BT_LOG_NONE; \
395 void __attribute__((constructor)) _bt_log_level_ctor(void) \
397 _level_sym = bt_log_get_level_from_env(_env_var_name); \
400 #endif /* BABELTRACE_LOGGING_LOG_API_H */