logging: strip down and clean `log.h` and `log.c`
[babeltrace.git] / src / logging / log-api.h
CommitLineData
71436ae4
SM
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 */
31enum 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
92extern "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 */
103void 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 */
111void 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 */
124void 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 */
133void 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 */
153void 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 */
161void 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 */
270static inline
271char 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 */
308static inline
309int 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 */
342static inline
343int 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 */
354static inline
355enum 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
373end:
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.037396 seconds and 4 git commands to generate.