| 1 | /* |
| 2 | * SPDX-License-Identifier: MIT |
| 3 | * |
| 4 | * Copyright (c) 2016 wonder-mice |
| 5 | * |
| 6 | * This is zf_log.h, modified with Babeltrace prefixes. |
| 7 | * See <https://github.com/wonder-mice/zf_log/>. |
| 8 | */ |
| 9 | |
| 10 | #pragma once |
| 11 | |
| 12 | #ifndef BABELTRACE_LOGGING_INTERNAL_H |
| 13 | #define BABELTRACE_LOGGING_INTERNAL_H |
| 14 | |
| 15 | #include <errno.h> |
| 16 | #include <stdlib.h> |
| 17 | #include <stdio.h> |
| 18 | #include <string.h> |
| 19 | #include <babeltrace2/babeltrace.h> |
| 20 | |
| 21 | /* Access private __BT_LOGGING_LEVEL_* macros. */ |
| 22 | #define __BT_IN_BABELTRACE_H |
| 23 | #include <babeltrace2/logging-defs.h> |
| 24 | #undef __BT_IN_BABELTRACE_H |
| 25 | |
| 26 | #include "common/macros.h" |
| 27 | #include "common/assert.h" |
| 28 | |
| 29 | /* To detect incompatible changes you can define BT_LOG_VERSION_REQUIRED to be |
| 30 | * the current value of BT_LOG_VERSION before including this file (or via |
| 31 | * compiler command line): |
| 32 | * |
| 33 | * #define BT_LOG_VERSION_REQUIRED 4 |
| 34 | * #include "logging.h" |
| 35 | * |
| 36 | * Compilation will fail when included file has different version. |
| 37 | */ |
| 38 | #define BT_LOG_VERSION 4 |
| 39 | #if defined(BT_LOG_VERSION_REQUIRED) |
| 40 | #if BT_LOG_VERSION_REQUIRED != BT_LOG_VERSION |
| 41 | #error different bt_log version required |
| 42 | #endif |
| 43 | #endif |
| 44 | |
| 45 | /* Log level guideline: |
| 46 | * - BT_LOG_FATAL - happened something impossible and absolutely unexpected. |
| 47 | * Process can't continue and must be terminated. |
| 48 | * Example: division by zero, unexpected modifications from other thread. |
| 49 | * - BT_LOG_ERROR - happened something possible, but highly unexpected. The |
| 50 | * process is able to recover and continue execution. |
| 51 | * Example: out of memory (could also be FATAL if not handled properly). |
| 52 | * - BT_LOG_WARNING - happened something that *usually* should not happen and |
| 53 | * significantly changes application behavior for some period of time. |
| 54 | * Example: configuration file not found, auth error. |
| 55 | * - BT_LOG_INFO - happened significant life cycle event or major state |
| 56 | * transition. |
| 57 | * Example: app started, user logged in. |
| 58 | * - BT_LOG_DEBUG - minimal set of events that could help to reconstruct the |
| 59 | * execution path. Usually disabled in release builds. |
| 60 | * - BT_LOG_TRACE - all other events. Usually disabled in release builds. |
| 61 | * |
| 62 | * *Ideally*, log file of debugged, well tested, production ready application |
| 63 | * should be empty or very small. Choosing a right log level is as important as |
| 64 | * providing short and self descriptive log message. |
| 65 | */ |
| 66 | #define BT_LOG_TRACE __BT_LOGGING_LEVEL_TRACE |
| 67 | #define BT_LOG_DEBUG __BT_LOGGING_LEVEL_DEBUG |
| 68 | #define BT_LOG_INFO __BT_LOGGING_LEVEL_INFO |
| 69 | #define BT_LOG_WARNING __BT_LOGGING_LEVEL_WARNING |
| 70 | #define BT_LOG_ERROR __BT_LOGGING_LEVEL_ERROR |
| 71 | #define BT_LOG_FATAL __BT_LOGGING_LEVEL_FATAL |
| 72 | #define BT_LOG_NONE __BT_LOGGING_LEVEL_NONE |
| 73 | |
| 74 | /* "Current" log level is a compile time check and has no runtime overhead. Log |
| 75 | * level that is below current log level it said to be "disabled". |
| 76 | * Otherwise, it's "enabled". Log messages that are disabled has no |
| 77 | * runtime overhead - they are converted to no-op by preprocessor and |
| 78 | * then eliminated by compiler. Current log level is configured per |
| 79 | * compilation module (.c/.cpp/.m file) by defining BT_LOG_DEF_LEVEL or |
| 80 | * BT_MINIMAL_LOG_LEVEL. BT_MINIMAL_LOG_LEVEL has higer priority and |
| 81 | * when defined overrides value provided by BT_LOG_DEF_LEVEL. |
| 82 | * |
| 83 | * Common practice is to define default current log level with BT_LOG_DEF_LEVEL |
| 84 | * in build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire |
| 85 | * project or target: |
| 86 | * |
| 87 | * CC_ARGS := -DBT_LOG_DEF_LEVEL=BT_LOG_INFO |
| 88 | * |
| 89 | * And when necessary to override it with BT_MINIMAL_LOG_LEVEL in .c/.cpp/.m files |
| 90 | * before including bt_log.h: |
| 91 | * |
| 92 | * #define BT_MINIMAL_LOG_LEVEL BT_LOG_TRACE |
| 93 | * #include "logging.h" |
| 94 | * |
| 95 | * If both BT_LOG_DEF_LEVEL and BT_MINIMAL_LOG_LEVEL are undefined, then |
| 96 | * BT_LOG_INFO will be used for release builds (BT_DEBUG_MODE is NOT |
| 97 | * defined) and BT_LOG_DEBUG otherwise (BT_DEBUG_MODE is defined). |
| 98 | */ |
| 99 | #if defined(BT_MINIMAL_LOG_LEVEL) |
| 100 | #define _BT_MINIMAL_LOG_LEVEL BT_MINIMAL_LOG_LEVEL |
| 101 | #elif defined(BT_LOG_DEF_LEVEL) |
| 102 | #define _BT_MINIMAL_LOG_LEVEL BT_LOG_DEF_LEVEL |
| 103 | #else |
| 104 | #ifdef BT_DEBUG_MODE |
| 105 | #define _BT_MINIMAL_LOG_LEVEL BT_LOG_DEBUG |
| 106 | #else |
| 107 | #define _BT_MINIMAL_LOG_LEVEL BT_LOG_INFO |
| 108 | #endif |
| 109 | #endif |
| 110 | |
| 111 | /* "Output" log level is a runtime check. When log level is below output log |
| 112 | * level it said to be "turned off" (or just "off" for short). Otherwise |
| 113 | * it's "turned on" (or just "on"). Log levels that were "disabled" (see |
| 114 | * BT_MINIMAL_LOG_LEVEL and BT_LOG_DEF_LEVEL) can't be "turned on", but |
| 115 | * "enabled" log levels could be "turned off". Only messages with log |
| 116 | * level which is "turned on" will reach output facility. All other |
| 117 | * messages will be ignored (and their arguments will not be evaluated). |
| 118 | * Output log level is a global property and configured per process |
| 119 | * using bt_log_set_output_level() function which can be called at any |
| 120 | * time. |
| 121 | * |
| 122 | * Though in some cases it could be useful to configure output log level per |
| 123 | * compilation module or per library. There are two ways to achieve that: |
| 124 | * - Define BT_LOG_OUTPUT_LEVEL to expresion that evaluates to desired output |
| 125 | * log level. |
| 126 | * - Copy bt_log.h and bt_log.c files into your library and build it with |
| 127 | * BT_LOG_LIBRARY_PREFIX defined to library specific prefix. See |
| 128 | * BT_LOG_LIBRARY_PREFIX for more details. |
| 129 | * |
| 130 | * When defined, BT_LOG_OUTPUT_LEVEL must evaluate to integral value |
| 131 | * that corresponds to desired output log level. Use it only when |
| 132 | * compilation module is required to have output log level which is |
| 133 | * different from global output log level set by |
| 134 | * bt_log_set_output_level() function. For other cases, consider |
| 135 | * defining BT_MINIMAL_LOG_LEVEL or using bt_log_set_output_level() |
| 136 | * function. |
| 137 | * |
| 138 | * Example: |
| 139 | * |
| 140 | * #define BT_LOG_OUTPUT_LEVEL g_module_log_level |
| 141 | * #include "logging.h" |
| 142 | * static int g_module_log_level = BT_LOG_INFO; |
| 143 | * static void foo() { |
| 144 | * BT_LOGI("Will check g_module_log_level for output log level"); |
| 145 | * } |
| 146 | * void debug_log(bool on) { |
| 147 | * g_module_log_level = on? BT_LOG_DEBUG: BT_LOG_INFO; |
| 148 | * } |
| 149 | * |
| 150 | * Note on performance. This expression will be evaluated each time |
| 151 | * message is logged (except when message log level is "disabled" - see |
| 152 | * BT_MINIMAL_LOG_LEVEL for details). Keep this expression as simple as |
| 153 | * possible, otherwise it will not only add runtime overhead, but also |
| 154 | * will increase size of call site (which will result in larger |
| 155 | * executable). The prefered way is to use integer variable (as in |
| 156 | * example above). If structure must be used, log_level field must be |
| 157 | * the first field in this structure: |
| 158 | * |
| 159 | * #define BT_LOG_OUTPUT_LEVEL (g_config.log_level) |
| 160 | * #include "logging.h" |
| 161 | * struct config { |
| 162 | * int log_level; |
| 163 | * unsigned other_field; |
| 164 | * [...] |
| 165 | * }; |
| 166 | * static config g_config = {BT_LOG_INFO, 0, ...}; |
| 167 | * |
| 168 | * This allows compiler to generate more compact load instruction (no need to |
| 169 | * specify offset since it's zero). Calling a function to get output log level |
| 170 | * is generaly a bad idea, since it will increase call site size and runtime |
| 171 | * overhead even further. |
| 172 | */ |
| 173 | #if defined(BT_LOG_OUTPUT_LEVEL) |
| 174 | #define _BT_LOG_OUTPUT_LEVEL BT_LOG_OUTPUT_LEVEL |
| 175 | #else |
| 176 | /* |
| 177 | * We disallow this to make sure Babeltrace modules always |
| 178 | * have their own local log level. |
| 179 | */ |
| 180 | #error No log level symbol specified: please define BT_LOG_OUTPUT_LEVEL before including this header. |
| 181 | #endif |
| 182 | |
| 183 | /* "Tag" is a compound string that could be associated with a log message. It |
| 184 | * consists of tag prefix and tag (both are optional). |
| 185 | * |
| 186 | * Tag prefix is a global property and configured per process using |
| 187 | * bt_log_set_tag_prefix() function. Tag prefix identifies context in which |
| 188 | * component or module is running (e.g. process name). For example, the same |
| 189 | * library could be used in both client and server processes that work on the |
| 190 | * same machine. Tag prefix could be used to easily distinguish between them. |
| 191 | * For more details about tag prefix see bt_log_set_tag_prefix() function. Tag |
| 192 | * prefix |
| 193 | * |
| 194 | * Tag identifies component or module. It is configured per compilation module |
| 195 | * (.c/.cpp/.m file) by defining BT_LOG_TAG or BT_LOG_DEF_TAG. BT_LOG_TAG has |
| 196 | * higer priority and when defined overrides value provided by BT_LOG_DEF_TAG. |
| 197 | * When defined, value must evaluate to (const char *), so for strings double |
| 198 | * quotes must be used. |
| 199 | * |
| 200 | * Default tag could be defined with BT_LOG_DEF_TAG in build script (e.g. |
| 201 | * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target: |
| 202 | * |
| 203 | * CC_ARGS := -DBT_LOG_DEF_TAG=\"MISC\" |
| 204 | * |
| 205 | * And when necessary could be overriden with BT_LOG_TAG in .c/.cpp/.m files |
| 206 | * before including bt_log.h: |
| 207 | * |
| 208 | * #define BT_LOG_TAG "MAIN" |
| 209 | * #include "logging.h" |
| 210 | * |
| 211 | * If both BT_LOG_DEF_TAG and BT_LOG_TAG are undefined no tag will be added to |
| 212 | * the log message (tag prefix still could be added though). |
| 213 | * |
| 214 | * Output example: |
| 215 | * |
| 216 | * 04-29 22:43:20.244 40059 1299 I hello.MAIN Number of arguments: 1 |
| 217 | * | | |
| 218 | * | +- tag (e.g. module) |
| 219 | * +- tag prefix (e.g. process name) |
| 220 | */ |
| 221 | #if defined(BT_LOG_TAG) |
| 222 | #define _BT_LOG_TAG BT_LOG_TAG |
| 223 | #elif defined(BT_LOG_DEF_TAG) |
| 224 | #define _BT_LOG_TAG BT_LOG_DEF_TAG |
| 225 | #else |
| 226 | #define _BT_LOG_TAG 0 |
| 227 | #endif |
| 228 | |
| 229 | /* Source location is part of a log line that describes location (function or |
| 230 | * method name, file name and line number, e.g. "runloop@main.cpp:68") of a |
| 231 | * log statement that produced it. |
| 232 | * Source location formats are: |
| 233 | * - BT_LOG_SRCLOC_NONE - don't add source location to log line. |
| 234 | * - BT_LOG_SRCLOC_SHORT - add source location in short form (file and line |
| 235 | * number, e.g. "@main.cpp:68"). |
| 236 | * - BT_LOG_SRCLOC_LONG - add source location in long form (function or method |
| 237 | * name, file and line number, e.g. "runloop@main.cpp:68"). |
| 238 | */ |
| 239 | #define BT_LOG_SRCLOC_NONE 0 |
| 240 | #define BT_LOG_SRCLOC_SHORT 1 |
| 241 | #define BT_LOG_SRCLOC_LONG 2 |
| 242 | |
| 243 | #define _BT_LOG_SRCLOC BT_LOG_SRCLOC_LONG |
| 244 | |
| 245 | #if BT_LOG_SRCLOC_LONG == _BT_LOG_SRCLOC |
| 246 | #define _BT_LOG_SRCLOC_FUNCTION _BT_LOG_FUNCTION |
| 247 | #else |
| 248 | #define _BT_LOG_SRCLOC_FUNCTION 0 |
| 249 | #endif |
| 250 | |
| 251 | /* Censoring provides conditional logging of secret information, also known as |
| 252 | * Personally Identifiable Information (PII) or Sensitive Personal Information |
| 253 | * (SPI). Censoring can be either enabled (BT_LOG_CENSORED) or disabled |
| 254 | * (BT_LOG_UNCENSORED). When censoring is enabled, log statements marked as |
| 255 | * "secrets" will be ignored and will have zero overhead (arguments also will |
| 256 | * not be evaluated). |
| 257 | */ |
| 258 | #define BT_LOG_CENSORED 1 |
| 259 | #define BT_LOG_UNCENSORED 0 |
| 260 | |
| 261 | /* Censoring is configured per compilation module (.c/.cpp/.m file) by defining |
| 262 | * BT_LOG_DEF_CENSORING or BT_LOG_CENSORING. BT_LOG_CENSORING has higer priority |
| 263 | * and when defined overrides value provided by BT_LOG_DEF_CENSORING. |
| 264 | * |
| 265 | * Common practice is to define default censoring with BT_LOG_DEF_CENSORING in |
| 266 | * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire |
| 267 | * project or target: |
| 268 | * |
| 269 | * CC_ARGS := -DBT_LOG_DEF_CENSORING=BT_LOG_CENSORED |
| 270 | * |
| 271 | * And when necessary to override it with BT_LOG_CENSORING in .c/.cpp/.m files |
| 272 | * before including bt_log.h (consider doing it only for debug purposes and be |
| 273 | * very careful not to push such temporary changes to source control): |
| 274 | * |
| 275 | * #define BT_LOG_CENSORING BT_LOG_UNCENSORED |
| 276 | * #include "logging.h" |
| 277 | * |
| 278 | * If both BT_LOG_DEF_CENSORING and BT_LOG_CENSORING are undefined, then |
| 279 | * BT_LOG_CENSORED will be used for release builds (BT_DEBUG_MODE is NOT |
| 280 | * defined) and BT_LOG_UNCENSORED otherwise (BT_DEBUG_MODE is defined). |
| 281 | */ |
| 282 | #if defined(BT_LOG_CENSORING) |
| 283 | #define _BT_LOG_CENSORING BT_LOG_CENSORING |
| 284 | #elif defined(BT_LOG_DEF_CENSORING) |
| 285 | #define _BT_LOG_CENSORING BT_LOG_DEF_CENSORING |
| 286 | #else |
| 287 | #ifdef BT_DEBUG_MODE |
| 288 | #define _BT_LOG_CENSORING BT_LOG_UNCENSORED |
| 289 | #else |
| 290 | #define _BT_LOG_CENSORING BT_LOG_CENSORED |
| 291 | #endif |
| 292 | #endif |
| 293 | |
| 294 | /* Check censoring at compile time. Evaluates to true when censoring is disabled |
| 295 | * (i.e. when secrets will be logged). For example: |
| 296 | * |
| 297 | * #if BT_LOG_SECRETS |
| 298 | * char ssn[16]; |
| 299 | * getSocialSecurityNumber(ssn); |
| 300 | * BT_LOGI("Customer ssn: %s", ssn); |
| 301 | * #endif |
| 302 | * |
| 303 | * See BT_LOG_SECRET() macro for a more convenient way of guarding single log |
| 304 | * statement. |
| 305 | */ |
| 306 | #define BT_LOG_SECRETS (BT_LOG_UNCENSORED == _BT_LOG_CENSORING) |
| 307 | |
| 308 | /* Static (compile-time) initialization support allows to configure logging |
| 309 | * before entering main() function. This mostly useful in C++ where functions |
| 310 | * and methods could be called during initialization of global objects. Those |
| 311 | * functions and methods could record log messages too and for that reason |
| 312 | * static initialization of logging configuration is customizable. |
| 313 | * |
| 314 | * Macros below allow to specify values to use for initial configuration: |
| 315 | * - BT_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none) |
| 316 | * - BT_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see |
| 317 | * BT_LOG_MEM_WIDTH in bt_log.c) |
| 318 | * - BT_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default: stderr or |
| 319 | * platform specific, see BT_LOG_USE_XXX macros in bt_log.c) |
| 320 | * - BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level (default: 0 - |
| 321 | * all levals are "turned on") |
| 322 | * |
| 323 | * For example, in log_config.c: |
| 324 | * |
| 325 | * #include "logging.h" |
| 326 | * BT_LOG_DEFINE_TAG_PREFIX = "MyApp"; |
| 327 | * BT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH}; |
| 328 | * BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_PUT_STD, custom_output_callback, 0}; |
| 329 | * BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = BT_LOG_INFO; |
| 330 | * |
| 331 | * However, to use any of those macros bt_log library must be compiled with |
| 332 | * following macros defined: |
| 333 | * - to use BT_LOG_DEFINE_TAG_PREFIX define BT_LOG_EXTERN_TAG_PREFIX |
| 334 | * - to use BT_LOG_DEFINE_GLOBAL_FORMAT define BT_LOG_EXTERN_GLOBAL_FORMAT |
| 335 | * - to use BT_LOG_DEFINE_GLOBAL_OUTPUT define BT_LOG_EXTERN_GLOBAL_OUTPUT |
| 336 | * - to use BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define |
| 337 | * BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL |
| 338 | * |
| 339 | * When bt_log library compiled with one of BT_LOG_EXTERN_XXX macros defined, |
| 340 | * corresponding BT_LOG_DEFINE_XXX macro MUST be used exactly once somewhere. |
| 341 | * Otherwise build will fail with link error (undefined symbol). |
| 342 | */ |
| 343 | #define BT_LOG_DEFINE_TAG_PREFIX BT_HIDDEN const char *_bt_log_tag_prefix |
| 344 | #define BT_LOG_DEFINE_GLOBAL_FORMAT BT_HIDDEN bt_log_format _bt_log_global_format |
| 345 | #define BT_LOG_DEFINE_GLOBAL_OUTPUT BT_HIDDEN bt_log_output _bt_log_global_output |
| 346 | #define BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL BT_HIDDEN int _bt_log_global_output_lvl |
| 347 | |
| 348 | /* Pointer to global format options. Direct modification is not allowed. Use |
| 349 | * bt_log_set_mem_width() instead. Could be used to initialize bt_log_spec |
| 350 | * structure: |
| 351 | * |
| 352 | * const bt_log_output g_output = {BT_LOG_PUT_STD, output_callback, 0}; |
| 353 | * const bt_log_spec g_spec = {BT_LOG_GLOBAL_FORMAT, &g_output}; |
| 354 | * BT_LOGI_AUX(&g_spec, "Hello"); |
| 355 | */ |
| 356 | #define BT_LOG_GLOBAL_FORMAT ((const bt_log_format *)&_bt_log_global_format) |
| 357 | |
| 358 | /* Pointer to global output variable. Direct modification is not allowed. Use |
| 359 | * bt_log_set_output_v() or bt_log_set_output_p() instead. Could be used to |
| 360 | * initialize bt_log_spec structure: |
| 361 | * |
| 362 | * const bt_log_format g_format = {40}; |
| 363 | * const bt_log_spec g_spec = {g_format, BT_LOG_GLOBAL_OUTPUT}; |
| 364 | * BT_LOGI_AUX(&g_spec, "Hello"); |
| 365 | */ |
| 366 | #define BT_LOG_GLOBAL_OUTPUT ((const bt_log_output *)&_bt_log_global_output) |
| 367 | |
| 368 | /* When defined, all library symbols produced by linker will be prefixed with |
| 369 | * provided value. That allows to use bt_log library privately in another |
| 370 | * libraries without exposing bt_log symbols in their original form (to avoid |
| 371 | * possible conflicts with other libraries / components that also could use |
| 372 | * bt_log for logging). Value must be without quotes, for example: |
| 373 | * |
| 374 | * CC_ARGS := -DBT_LOG_LIBRARY_PREFIX=my_lib_ |
| 375 | * |
| 376 | * Note, that in this mode BT_LOG_LIBRARY_PREFIX must be defined when building |
| 377 | * bt_log library AND it also must be defined to the same value when building |
| 378 | * a library that uses it. For example, consider fictional KittyHttp library |
| 379 | * that wants to use bt_log for logging. First approach that could be taken is |
| 380 | * to add bt_log.h and bt_log.c to the KittyHttp's source code tree directly. |
| 381 | * In that case it will be enough just to define BT_LOG_LIBRARY_PREFIX in |
| 382 | * KittyHttp's build script: |
| 383 | * |
| 384 | * // KittyHttp/CMakeLists.txt |
| 385 | * target_compile_definitions(KittyHttp PRIVATE |
| 386 | * "BT_LOG_LIBRARY_PREFIX=KittyHttp_") |
| 387 | * |
| 388 | * If KittyHttp doesn't want to include bt_log source code in its source tree |
| 389 | * and wants to build bt_log as a separate library than bt_log library must be |
| 390 | * built with BT_LOG_LIBRARY_PREFIX defined to KittyHttp_ AND KittyHttp library |
| 391 | * itself also needs to define BT_LOG_LIBRARY_PREFIX to KittyHttp_. It can do |
| 392 | * so either in its build script, as in example above, or by providing a |
| 393 | * wrapper header that KittyHttp library will need to use instead of bt_log.h: |
| 394 | * |
| 395 | * // KittyHttpLogging.h |
| 396 | * #define BT_LOG_LIBRARY_PREFIX KittyHttp_ |
| 397 | * #include "logging.h" |
| 398 | * |
| 399 | * Regardless of the method chosen, the end result is that bt_log symbols will |
| 400 | * be prefixed with "KittyHttp_", so if a user of KittyHttp (say DogeBrowser) |
| 401 | * also uses bt_log for logging, they will not interferer with each other. Both |
| 402 | * will have their own log level, output facility, format options etc. |
| 403 | */ |
| 404 | #ifdef BT_LOG_LIBRARY_PREFIX |
| 405 | #define _BT_LOG_DECOR__(prefix, name) prefix ## name |
| 406 | #define _BT_LOG_DECOR_(prefix, name) _BT_LOG_DECOR__(prefix, name) |
| 407 | #define _BT_LOG_DECOR(name) _BT_LOG_DECOR_(BT_LOG_LIBRARY_PREFIX, name) |
| 408 | |
| 409 | #define bt_log_set_tag_prefix _BT_LOG_DECOR(bt_log_set_tag_prefix) |
| 410 | #define bt_log_set_mem_width _BT_LOG_DECOR(bt_log_set_mem_width) |
| 411 | #define bt_log_set_output_level _BT_LOG_DECOR(bt_log_set_output_level) |
| 412 | #define bt_log_set_output_v _BT_LOG_DECOR(bt_log_set_output_v) |
| 413 | #define bt_log_set_output_p _BT_LOG_DECOR(bt_log_set_output_p) |
| 414 | #define bt_log_out_stderr_callback _BT_LOG_DECOR(bt_log_out_stderr_callback) |
| 415 | #define _bt_log_tag_prefix _BT_LOG_DECOR(_bt_log_tag_prefix) |
| 416 | #define _bt_log_global_format _BT_LOG_DECOR(_bt_log_global_format) |
| 417 | #define _bt_log_global_output _BT_LOG_DECOR(_bt_log_global_output) |
| 418 | #define _bt_log_global_output_lvl _BT_LOG_DECOR(_bt_log_global_output_lvl) |
| 419 | #define _bt_log_write_d _BT_LOG_DECOR(_bt_log_write_d) |
| 420 | #define _bt_log_write_aux_d _BT_LOG_DECOR(_bt_log_write_aux_d) |
| 421 | #define _bt_log_write _BT_LOG_DECOR(_bt_log_write) |
| 422 | #define _bt_log_write_aux _BT_LOG_DECOR(_bt_log_write_aux) |
| 423 | #define _bt_log_write_mem_d _BT_LOG_DECOR(_bt_log_write_mem_d) |
| 424 | #define _bt_log_write_mem_aux_d _BT_LOG_DECOR(_bt_log_write_mem_aux_d) |
| 425 | #define _bt_log_write_mem _BT_LOG_DECOR(_bt_log_write_mem) |
| 426 | #define _bt_log_write_mem_aux _BT_LOG_DECOR(_bt_log_write_mem_aux) |
| 427 | #define _bt_log_stderr_spec _BT_LOG_DECOR(_bt_log_stderr_spec) |
| 428 | #endif |
| 429 | |
| 430 | #if defined(__printflike) |
| 431 | #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \ |
| 432 | __printflike(str_index, first_to_check) |
| 433 | #elif defined(__MINGW_PRINTF_FORMAT) |
| 434 | #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \ |
| 435 | __attribute__((format(__MINGW_PRINTF_FORMAT, str_index, first_to_check))) |
| 436 | #elif defined(__GNUC__) |
| 437 | #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \ |
| 438 | __attribute__((format(__printf__, str_index, first_to_check))) |
| 439 | #else |
| 440 | #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) |
| 441 | #endif |
| 442 | |
| 443 | #if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__) |
| 444 | #define _BT_LOG_FUNCTION __FUNCTION__ |
| 445 | #else |
| 446 | #define _BT_LOG_FUNCTION __func__ |
| 447 | #endif |
| 448 | |
| 449 | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) |
| 450 | #define _BT_LOG_INLINE __inline |
| 451 | #define _BT_LOG_IF(cond) \ |
| 452 | __pragma(warning(push)) \ |
| 453 | __pragma(warning(disable:4127)) \ |
| 454 | if(cond) \ |
| 455 | __pragma(warning(pop)) |
| 456 | #define _BT_LOG_WHILE(cond) \ |
| 457 | __pragma(warning(push)) \ |
| 458 | __pragma(warning(disable:4127)) \ |
| 459 | while(cond) \ |
| 460 | __pragma(warning(pop)) |
| 461 | #else |
| 462 | #define _BT_LOG_INLINE inline |
| 463 | #define _BT_LOG_IF(cond) if(cond) |
| 464 | #define _BT_LOG_WHILE(cond) while(cond) |
| 465 | #endif |
| 466 | #define _BT_LOG_NEVER _BT_LOG_IF(0) |
| 467 | #define _BT_LOG_ONCE _BT_LOG_WHILE(0) |
| 468 | |
| 469 | #ifdef __cplusplus |
| 470 | extern "C" { |
| 471 | #endif |
| 472 | |
| 473 | /* Set tag prefix. Prefix will be separated from the tag with dot ('.'). |
| 474 | * Use 0 or empty string to disable (default). Common use is to set it to |
| 475 | * the process (or build target) name (e.g. to separate client and server |
| 476 | * processes). Function will NOT copy provided prefix string, but will store the |
| 477 | * pointer. Hence specified prefix string must remain valid. See |
| 478 | * BT_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main() function. |
| 479 | * See BT_LOG_TAG for more information about tag and tag prefix. |
| 480 | */ |
| 481 | void bt_log_set_tag_prefix(const char *const prefix); |
| 482 | |
| 483 | /* Set number of bytes per log line in memory (ASCII-HEX) output. Example: |
| 484 | * |
| 485 | * I hello.MAIN 4c6f72656d20697073756d20646f6c6f Lorem ipsum dolo |
| 486 | * |<- w bytes ->| |<- w chars ->| |
| 487 | * |
| 488 | * See BT_LOGF_MEM and BT_LOGF_MEM_AUX for more details. |
| 489 | */ |
| 490 | void bt_log_set_mem_width(const unsigned w); |
| 491 | |
| 492 | /* Set "output" log level. See BT_MINIMAL_LOG_LEVEL and BT_LOG_OUTPUT_LEVEL for more |
| 493 | * info about log levels. |
| 494 | */ |
| 495 | void bt_log_set_output_level(const int lvl); |
| 496 | |
| 497 | /* Put mask is a set of flags that define what fields will be added to each |
| 498 | * log message. Default value is BT_LOG_PUT_STD and other flags could be used to |
| 499 | * alter its behavior. See bt_log_set_output_v() for more details. |
| 500 | * |
| 501 | * Note about BT_LOG_PUT_SRC: it will be added only in debug builds |
| 502 | * (BT_DEBUG_MODE is defined). |
| 503 | */ |
| 504 | enum |
| 505 | { |
| 506 | BT_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */ |
| 507 | BT_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */ |
| 508 | BT_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */ |
| 509 | BT_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */ |
| 510 | BT_LOG_PUT_STD = 0xffff, /* everything (default) */ |
| 511 | }; |
| 512 | |
| 513 | typedef struct bt_log_message |
| 514 | { |
| 515 | int lvl; /* Log level of the message */ |
| 516 | const char *tag; /* Associated tag (without tag prefix) */ |
| 517 | char *buf; /* Buffer start */ |
| 518 | char *e; /* Buffer end (last position where EOL with 0 could be written) */ |
| 519 | char *p; /* Buffer content end (append position) */ |
| 520 | char *tag_b; /* Prefixed tag start */ |
| 521 | char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */ |
| 522 | char *msg_b; /* Message start (expanded format string) */ |
| 523 | } |
| 524 | bt_log_message; |
| 525 | |
| 526 | /* Type of output callback function. It will be called for each log line allowed |
| 527 | * by both "current" and "output" log levels ("enabled" and "turned on"). |
| 528 | * Callback function is allowed to modify content of the buffers pointed by the |
| 529 | * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg |
| 530 | * is UTF-8 encoded (no BOM mark). |
| 531 | */ |
| 532 | typedef void (*bt_log_output_cb)(const bt_log_message *msg, void *arg); |
| 533 | |
| 534 | /* Format options. For more details see bt_log_set_mem_width(). |
| 535 | */ |
| 536 | typedef struct bt_log_format |
| 537 | { |
| 538 | unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */ |
| 539 | } |
| 540 | bt_log_format; |
| 541 | |
| 542 | /* Output facility. |
| 543 | */ |
| 544 | typedef struct bt_log_output |
| 545 | { |
| 546 | unsigned mask; /* What to put into log line buffer (see BT_LOG_PUT_XXX) */ |
| 547 | void *arg; /* User provided output callback argument */ |
| 548 | bt_log_output_cb callback; /* Output callback function */ |
| 549 | } |
| 550 | bt_log_output; |
| 551 | |
| 552 | /* Set output callback function. |
| 553 | * |
| 554 | * Mask allows to control what information will be added to the log line buffer |
| 555 | * before callback function is invoked. Default mask value is BT_LOG_PUT_STD. |
| 556 | */ |
| 557 | void bt_log_set_output_v(const unsigned mask, void *const arg, |
| 558 | const bt_log_output_cb callback); |
| 559 | static _BT_LOG_INLINE void bt_log_set_output_p(const bt_log_output *const output) |
| 560 | { |
| 561 | bt_log_set_output_v(output->mask, output->arg, output->callback); |
| 562 | } |
| 563 | |
| 564 | /* Used with _AUX macros and allows to override global format and output |
| 565 | * facility. Use BT_LOG_GLOBAL_FORMAT and BT_LOG_GLOBAL_OUTPUT for values from |
| 566 | * global configuration. Example: |
| 567 | * |
| 568 | * static const bt_log_output module_output = { |
| 569 | * BT_LOG_PUT_STD, 0, custom_output_callback |
| 570 | * }; |
| 571 | * static const bt_log_spec module_spec = { |
| 572 | * BT_LOG_GLOBAL_FORMAT, &module_output |
| 573 | * }; |
| 574 | * BT_LOGI_AUX(&module_spec, "Position: %ix%i", x, y); |
| 575 | * |
| 576 | * See BT_LOGF_AUX and BT_LOGF_MEM_AUX for details. |
| 577 | */ |
| 578 | typedef struct bt_log_spec |
| 579 | { |
| 580 | const bt_log_format *format; |
| 581 | const bt_log_output *output; |
| 582 | } |
| 583 | bt_log_spec; |
| 584 | |
| 585 | #ifdef __cplusplus |
| 586 | } |
| 587 | #endif |
| 588 | |
| 589 | /* Execute log statement if condition is true. Example: |
| 590 | * |
| 591 | * BT_LOG_IF(1 < 2, BT_LOGI("Log this")); |
| 592 | * BT_LOG_IF(1 > 2, BT_LOGI("Don't log this")); |
| 593 | * |
| 594 | * Keep in mind though, that if condition can't be evaluated at compile time, |
| 595 | * then it will be evaluated at run time. This will increase exectuable size |
| 596 | * and can have noticeable performance overhead. Try to limit conditions to |
| 597 | * expressions that can be evaluated at compile time. |
| 598 | */ |
| 599 | #define BT_LOG_IF(cond, f) do { _BT_LOG_IF((cond)) { f; } } _BT_LOG_ONCE |
| 600 | |
| 601 | /* Mark log statement as "secret". Log statements that are marked as secrets |
| 602 | * will NOT be executed when censoring is enabled (see BT_LOG_CENSORED). |
| 603 | * Example: |
| 604 | * |
| 605 | * BT_LOG_SECRET(BT_LOGI("Credit card: %s", credit_card)); |
| 606 | * BT_LOG_SECRET(BT_LOGD_MEM(cipher, cipher_sz, "Cipher bytes:")); |
| 607 | */ |
| 608 | #define BT_LOG_SECRET(f) BT_LOG_IF(BT_LOG_SECRETS, f) |
| 609 | |
| 610 | /* Check "current" log level at compile time (ignoring "output" log level). |
| 611 | * Evaluates to true when specified log level is enabled. For example: |
| 612 | * |
| 613 | * #if BT_LOG_ENABLED_DEBUG |
| 614 | * const char *const g_enum_strings[] = { |
| 615 | * "enum_value_0", "enum_value_1", "enum_value_2" |
| 616 | * }; |
| 617 | * #endif |
| 618 | * // ... |
| 619 | * #if BT_LOG_ENABLED_DEBUG |
| 620 | * BT_LOGD("enum value: %s", g_enum_strings[v]); |
| 621 | * #endif |
| 622 | * |
| 623 | * See BT_MINIMAL_LOG_LEVEL for details. |
| 624 | */ |
| 625 | #define BT_LOG_ENABLED(lvl) ((lvl) >= _BT_MINIMAL_LOG_LEVEL) |
| 626 | #define BT_LOG_ENABLED_TRACE BT_LOG_ENABLED(BT_LOG_TRACE) |
| 627 | #define BT_LOG_ENABLED_DEBUG BT_LOG_ENABLED(BT_LOG_DEBUG) |
| 628 | #define BT_LOG_ENABLED_INFO BT_LOG_ENABLED(BT_LOG_INFO) |
| 629 | #define BT_LOG_ENABLED_WARNING BT_LOG_ENABLED(BT_LOG_WARNING) |
| 630 | #define BT_LOG_ENABLED_ERROR BT_LOG_ENABLED(BT_LOG_ERROR) |
| 631 | #define BT_LOG_ENABLED_FATAL BT_LOG_ENABLED(BT_LOG_FATAL) |
| 632 | |
| 633 | /* Check "output" log level at run time (taking into account "current" log |
| 634 | * level as well). Evaluates to true when specified log level is turned on AND |
| 635 | * enabled. For example: |
| 636 | * |
| 637 | * if (BT_LOG_ON_DEBUG) |
| 638 | * { |
| 639 | * char hash[65]; |
| 640 | * sha256(data_ptr, data_sz, hash); |
| 641 | * BT_LOGD("data: len=%u, sha256=%s", data_sz, hash); |
| 642 | * } |
| 643 | * |
| 644 | * See BT_LOG_OUTPUT_LEVEL for details. |
| 645 | */ |
| 646 | #define BT_LOG_ON_CUR_LVL(lvl, cur_lvl) \ |
| 647 | (BT_LOG_ENABLED((lvl)) && (lvl) >= (cur_lvl)) |
| 648 | #define BT_LOG_ON(lvl) \ |
| 649 | (BT_LOG_ENABLED((lvl)) && (lvl) >= _BT_LOG_OUTPUT_LEVEL) |
| 650 | #define BT_LOG_ON_TRACE BT_LOG_ON(BT_LOG_TRACE) |
| 651 | #define BT_LOG_ON_DEBUG BT_LOG_ON(BT_LOG_DEBUG) |
| 652 | #define BT_LOG_ON_INFO BT_LOG_ON(BT_LOG_INFO) |
| 653 | #define BT_LOG_ON_WARNING BT_LOG_ON(BT_LOG_WARNING) |
| 654 | #define BT_LOG_ON_ERROR BT_LOG_ON(BT_LOG_ERROR) |
| 655 | #define BT_LOG_ON_FATAL BT_LOG_ON(BT_LOG_FATAL) |
| 656 | |
| 657 | #ifdef __cplusplus |
| 658 | extern "C" { |
| 659 | #endif |
| 660 | |
| 661 | extern const char *_bt_log_tag_prefix; |
| 662 | extern bt_log_format _bt_log_global_format; |
| 663 | extern bt_log_output _bt_log_global_output; |
| 664 | extern int _bt_log_global_output_lvl; |
| 665 | extern const bt_log_spec _bt_log_stderr_spec; |
| 666 | |
| 667 | BT_HIDDEN |
| 668 | void _bt_log_write_d( |
| 669 | const char *const func, const char *const file, const unsigned line, |
| 670 | const int lvl, const char *const tag, |
| 671 | const char *const fmt, ...) _BT_LOG_PRINTFLIKE(6, 7); |
| 672 | |
| 673 | BT_HIDDEN |
| 674 | void _bt_log_write_aux_d( |
| 675 | const char *const func, const char *const file, const unsigned line, |
| 676 | const bt_log_spec *const log, const int lvl, const char *const tag, |
| 677 | const char *const fmt, ...) _BT_LOG_PRINTFLIKE(7, 8); |
| 678 | |
| 679 | BT_HIDDEN |
| 680 | void _bt_log_write( |
| 681 | const int lvl, const char *const tag, |
| 682 | const char *const fmt, ...) _BT_LOG_PRINTFLIKE(3, 4); |
| 683 | |
| 684 | BT_HIDDEN |
| 685 | void _bt_log_write_aux( |
| 686 | const bt_log_spec *const log, const int lvl, const char *const tag, |
| 687 | const char *const fmt, ...) _BT_LOG_PRINTFLIKE(4, 5); |
| 688 | |
| 689 | BT_HIDDEN |
| 690 | void _bt_log_write_mem_d( |
| 691 | const char *const func, const char *const file, const unsigned line, |
| 692 | const int lvl, const char *const tag, |
| 693 | const void *const d, const unsigned d_sz, |
| 694 | const char *const fmt, ...) _BT_LOG_PRINTFLIKE(8, 9); |
| 695 | |
| 696 | BT_HIDDEN |
| 697 | void _bt_log_write_mem_aux_d( |
| 698 | const char *const func, const char *const file, const unsigned line, |
| 699 | const bt_log_spec *const log, const int lvl, const char *const tag, |
| 700 | const void *const d, const unsigned d_sz, |
| 701 | const char *const fmt, ...) _BT_LOG_PRINTFLIKE(9, 10); |
| 702 | |
| 703 | BT_HIDDEN |
| 704 | void _bt_log_write_mem( |
| 705 | const int lvl, const char *const tag, |
| 706 | const void *const d, const unsigned d_sz, |
| 707 | const char *const fmt, ...) _BT_LOG_PRINTFLIKE(5, 6); |
| 708 | |
| 709 | BT_HIDDEN |
| 710 | void _bt_log_write_mem_aux( |
| 711 | const bt_log_spec *const log, const int lvl, const char *const tag, |
| 712 | const void *const d, const unsigned d_sz, |
| 713 | const char *const fmt, ...) _BT_LOG_PRINTFLIKE(6, 7); |
| 714 | |
| 715 | #ifdef __cplusplus |
| 716 | } |
| 717 | #endif |
| 718 | |
| 719 | /* Message logging macros: |
| 720 | * - BT_LOGT("format string", args, ...) |
| 721 | * - BT_LOGD("format string", args, ...) |
| 722 | * - BT_LOGI("format string", args, ...) |
| 723 | * - BT_LOGW("format string", args, ...) |
| 724 | * - BT_LOGE("format string", args, ...) |
| 725 | * - BT_LOGF("format string", args, ...) |
| 726 | * |
| 727 | * Message and error string (errno) logging macros: |
| 728 | * - BT_LOGT_ERRNO("initial message", "format string", args, ...) |
| 729 | * - BT_LOGD_ERRNO("initial message", "format string", args, ...) |
| 730 | * - BT_LOGI_ERRNO("initial message", "format string", args, ...) |
| 731 | * - BT_LOGW_ERRNO("initial message", "format string", args, ...) |
| 732 | * - BT_LOGE_ERRNO("initial message", "format string", args, ...) |
| 733 | * - BT_LOGF_ERRNO("initial message", "format string", args, ...) |
| 734 | * |
| 735 | * Memory logging macros: |
| 736 | * - BT_LOGT_MEM(data_ptr, data_sz, "format string", args, ...) |
| 737 | * - BT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...) |
| 738 | * - BT_LOGI_MEM(data_ptr, data_sz, "format string", args, ...) |
| 739 | * - BT_LOGW_MEM(data_ptr, data_sz, "format string", args, ...) |
| 740 | * - BT_LOGE_MEM(data_ptr, data_sz, "format string", args, ...) |
| 741 | * - BT_LOGF_MEM(data_ptr, data_sz, "format string", args, ...) |
| 742 | * |
| 743 | * Auxiliary logging macros: |
| 744 | * - BT_LOGT_AUX(&log_instance, "format string", args, ...) |
| 745 | * - BT_LOGD_AUX(&log_instance, "format string", args, ...) |
| 746 | * - BT_LOGI_AUX(&log_instance, "format string", args, ...) |
| 747 | * - BT_LOGW_AUX(&log_instance, "format string", args, ...) |
| 748 | * - BT_LOGE_AUX(&log_instance, "format string", args, ...) |
| 749 | * - BT_LOGF_AUX(&log_instance, "format string", args, ...) |
| 750 | * |
| 751 | * Auxiliary memory logging macros: |
| 752 | * - BT_LOGT_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...) |
| 753 | * - BT_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...) |
| 754 | * - BT_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...) |
| 755 | * - BT_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...) |
| 756 | * - BT_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...) |
| 757 | * - BT_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...) |
| 758 | * |
| 759 | * Preformatted string logging macros: |
| 760 | * - BT_LOGT_STR("preformatted string"); |
| 761 | * - BT_LOGD_STR("preformatted string"); |
| 762 | * - BT_LOGI_STR("preformatted string"); |
| 763 | * - BT_LOGW_STR("preformatted string"); |
| 764 | * - BT_LOGE_STR("preformatted string"); |
| 765 | * - BT_LOGF_STR("preformatted string"); |
| 766 | * |
| 767 | * Explicit log level and tag macros: |
| 768 | * - BT_LOG_WRITE(level, tag, "format string", args, ...) |
| 769 | * - BT_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string", args, ...) |
| 770 | * - BT_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args, ...) |
| 771 | * - BT_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz, |
| 772 | * "format string", args, ...) |
| 773 | * |
| 774 | * Explicit log level, current log level, and tag: |
| 775 | * - BT_LOG_WRITE_CUR_LVL(level, cur_level, tag, "format string", args, ...) |
| 776 | * |
| 777 | * Format string follows printf() conventions. Both data_ptr and data_sz could |
| 778 | * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments |
| 779 | * match format specifiers in format string. |
| 780 | * |
| 781 | * Library assuming UTF-8 encoding for all strings (char *), including format |
| 782 | * string itself. |
| 783 | */ |
| 784 | #if BT_LOG_SRCLOC_NONE == _BT_LOG_SRCLOC |
| 785 | #define BT_LOG_WRITE(lvl, tag, ...) \ |
| 786 | do { \ |
| 787 | if (BT_LOG_ON(lvl)) \ |
| 788 | _bt_log_write(lvl, tag, __VA_ARGS__); \ |
| 789 | } _BT_LOG_ONCE |
| 790 | #define BT_LOG_WRITE_CUR_LVL(lvl, cur_lvl, tag, ...) \ |
| 791 | do { \ |
| 792 | if (BT_LOG_ON_CUR_LVL((lvl), (cur_lvl))) \ |
| 793 | _bt_log_write(lvl, tag, __VA_ARGS__); \ |
| 794 | } _BT_LOG_ONCE |
| 795 | #define BT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \ |
| 796 | do { \ |
| 797 | if (BT_LOG_ON(lvl)) \ |
| 798 | _bt_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \ |
| 799 | } _BT_LOG_ONCE |
| 800 | #define BT_LOG_WRITE_AUX(log, lvl, tag, ...) \ |
| 801 | do { \ |
| 802 | if (BT_LOG_ON(lvl)) \ |
| 803 | _bt_log_write_aux(log, lvl, tag, __VA_ARGS__); \ |
| 804 | } _BT_LOG_ONCE |
| 805 | #define BT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \ |
| 806 | do { \ |
| 807 | if (BT_LOG_ON(lvl)) \ |
| 808 | _bt_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \ |
| 809 | } _BT_LOG_ONCE |
| 810 | #else |
| 811 | #define BT_LOG_WRITE(lvl, tag, ...) \ |
| 812 | do { \ |
| 813 | if (BT_LOG_ON(lvl)) \ |
| 814 | _bt_log_write_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \ |
| 815 | lvl, tag, __VA_ARGS__); \ |
| 816 | } _BT_LOG_ONCE |
| 817 | #define BT_LOG_WRITE_CUR_LVL(lvl, cur_lvl, tag, ...) \ |
| 818 | do { \ |
| 819 | if (BT_LOG_ON_CUR_LVL((lvl), (cur_lvl))) \ |
| 820 | _bt_log_write_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \ |
| 821 | lvl, tag, __VA_ARGS__); \ |
| 822 | } _BT_LOG_ONCE |
| 823 | #define BT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \ |
| 824 | do { \ |
| 825 | if (BT_LOG_ON(lvl)) \ |
| 826 | _bt_log_write_mem_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \ |
| 827 | lvl, tag, d, d_sz, __VA_ARGS__); \ |
| 828 | } _BT_LOG_ONCE |
| 829 | #define BT_LOG_WRITE_AUX(log, lvl, tag, ...) \ |
| 830 | do { \ |
| 831 | if (BT_LOG_ON(lvl)) \ |
| 832 | _bt_log_write_aux_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \ |
| 833 | log, lvl, tag, __VA_ARGS__); \ |
| 834 | } _BT_LOG_ONCE |
| 835 | #define BT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \ |
| 836 | do { \ |
| 837 | if (BT_LOG_ON(lvl)) \ |
| 838 | _bt_log_write_mem_aux_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \ |
| 839 | log, lvl, tag, d, d_sz, __VA_ARGS__); \ |
| 840 | } _BT_LOG_ONCE |
| 841 | #endif |
| 842 | |
| 843 | #define BT_LOG_WRITE_ERRNO_CUR_LVL(lvl, cur_lvl, tag, _msg, _fmt, args...) \ |
| 844 | do { \ |
| 845 | const char *error_str; \ |
| 846 | error_str = g_strerror(errno); \ |
| 847 | BT_LOG_WRITE_CUR_LVL(lvl, cur_lvl, tag, _msg ": %s" _fmt, error_str, ## args); \ |
| 848 | } _BT_LOG_ONCE |
| 849 | |
| 850 | #define BT_LOG_WRITE_ERRNO(lvl, tag, _msg, _fmt, args...) \ |
| 851 | do { \ |
| 852 | BT_LOG_WRITE_ERRNO_CUR_LVL(lvl, _BT_LOG_OUTPUT_LEVEL, tag, _msg, _fmt, ## args); \ |
| 853 | } _BT_LOG_ONCE |
| 854 | |
| 855 | static _BT_LOG_INLINE void _bt_log_unused(const int dummy, ...) {(void)dummy;} |
| 856 | |
| 857 | #define _BT_LOG_UNUSED(...) \ |
| 858 | do { _BT_LOG_NEVER _bt_log_unused(0, __VA_ARGS__); } _BT_LOG_ONCE |
| 859 | |
| 860 | #if BT_LOG_ENABLED_TRACE |
| 861 | #define BT_LOGT(...) \ |
| 862 | BT_LOG_WRITE(BT_LOG_TRACE, _BT_LOG_TAG, __VA_ARGS__) |
| 863 | #define BT_LOGT_ERRNO(...) \ |
| 864 | BT_LOG_WRITE_ERRNO(BT_LOG_TRACE, _BT_LOG_TAG, __VA_ARGS__) |
| 865 | #define BT_LOGT_AUX(log, ...) \ |
| 866 | BT_LOG_WRITE_AUX(log, BT_LOG_TRACE, _BT_LOG_TAG, __VA_ARGS__) |
| 867 | #define BT_LOGT_MEM(d, d_sz, ...) \ |
| 868 | BT_LOG_WRITE_MEM(BT_LOG_TRACE, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 869 | #define BT_LOGT_MEM_AUX(log, d, d_sz, ...) \ |
| 870 | BT_LOG_WRITE_MEM(log, BT_LOG_TRACE, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 871 | #else |
| 872 | #define BT_LOGT(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 873 | #define BT_LOGT_ERRNO(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 874 | #define BT_LOGT_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 875 | #define BT_LOGT_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 876 | #define BT_LOGT_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 877 | #endif |
| 878 | |
| 879 | #if BT_LOG_ENABLED_DEBUG |
| 880 | #define BT_LOGD(...) \ |
| 881 | BT_LOG_WRITE(BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__) |
| 882 | #define BT_LOGD_ERRNO(...) \ |
| 883 | BT_LOG_WRITE_ERRNO(BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__) |
| 884 | #define BT_LOGD_AUX(log, ...) \ |
| 885 | BT_LOG_WRITE_AUX(log, BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__) |
| 886 | #define BT_LOGD_MEM(d, d_sz, ...) \ |
| 887 | BT_LOG_WRITE_MEM(BT_LOG_DEBUG, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 888 | #define BT_LOGD_MEM_AUX(log, d, d_sz, ...) \ |
| 889 | BT_LOG_WRITE_MEM_AUX(log, BT_LOG_DEBUG, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 890 | #else |
| 891 | #define BT_LOGD(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 892 | #define BT_LOGD_ERRNO(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 893 | #define BT_LOGD_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 894 | #define BT_LOGD_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 895 | #define BT_LOGD_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 896 | #endif |
| 897 | |
| 898 | #if BT_LOG_ENABLED_INFO |
| 899 | #define BT_LOGI(...) \ |
| 900 | BT_LOG_WRITE(BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__) |
| 901 | #define BT_LOGI_ERRNO(...) \ |
| 902 | BT_LOG_WRITE_ERRNO(BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__) |
| 903 | #define BT_LOGI_AUX(log, ...) \ |
| 904 | BT_LOG_WRITE_AUX(log, BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__) |
| 905 | #define BT_LOGI_MEM(d, d_sz, ...) \ |
| 906 | BT_LOG_WRITE_MEM(BT_LOG_INFO, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 907 | #define BT_LOGI_MEM_AUX(log, d, d_sz, ...) \ |
| 908 | BT_LOG_WRITE_MEM_AUX(log, BT_LOG_INFO, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 909 | #else |
| 910 | #define BT_LOGI(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 911 | #define BT_LOGI_ERRNO(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 912 | #define BT_LOGI_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 913 | #define BT_LOGI_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 914 | #define BT_LOGI_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 915 | #endif |
| 916 | |
| 917 | #if BT_LOG_ENABLED_WARNING |
| 918 | #define BT_LOGW(...) \ |
| 919 | BT_LOG_WRITE(BT_LOG_WARNING, _BT_LOG_TAG, __VA_ARGS__) |
| 920 | #define BT_LOGW_ERRNO(...) \ |
| 921 | BT_LOG_WRITE_ERRNO(BT_LOG_WARNING, _BT_LOG_TAG, __VA_ARGS__) |
| 922 | #define BT_LOGW_AUX(log, ...) \ |
| 923 | BT_LOG_WRITE_AUX(log, BT_LOG_WARNING, _BT_LOG_TAG, __VA_ARGS__) |
| 924 | #define BT_LOGW_MEM(d, d_sz, ...) \ |
| 925 | BT_LOG_WRITE_MEM(BT_LOG_WARNING, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 926 | #define BT_LOGW_MEM_AUX(log, d, d_sz, ...) \ |
| 927 | BT_LOG_WRITE_MEM_AUX(log, BT_LOG_WARNING, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 928 | #else |
| 929 | #define BT_LOGW(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 930 | #define BT_LOGW_ERRNO(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 931 | #define BT_LOGW_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 932 | #define BT_LOGW_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 933 | #define BT_LOGW_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 934 | #endif |
| 935 | |
| 936 | #if BT_LOG_ENABLED_ERROR |
| 937 | #define BT_LOGE(...) \ |
| 938 | BT_LOG_WRITE(BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__) |
| 939 | #define BT_LOGE_ERRNO(...) \ |
| 940 | BT_LOG_WRITE_ERRNO(BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__) |
| 941 | #define BT_LOGE_AUX(log, ...) \ |
| 942 | BT_LOG_WRITE_AUX(log, BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__) |
| 943 | #define BT_LOGE_MEM(d, d_sz, ...) \ |
| 944 | BT_LOG_WRITE_MEM(BT_LOG_ERROR, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 945 | #define BT_LOGE_MEM_AUX(log, d, d_sz, ...) \ |
| 946 | BT_LOG_WRITE_MEM_AUX(log, BT_LOG_ERROR, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 947 | #else |
| 948 | #define BT_LOGE(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 949 | #define BT_LOGE_ERRNO(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 950 | #define BT_LOGE_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 951 | #define BT_LOGE_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 952 | #define BT_LOGE_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 953 | #endif |
| 954 | |
| 955 | #if BT_LOG_ENABLED_FATAL |
| 956 | #define BT_LOGF(...) \ |
| 957 | BT_LOG_WRITE(BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__) |
| 958 | #define BT_LOGF_ERRNO(...) \ |
| 959 | BT_LOG_WRITE_ERRNO(BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__) |
| 960 | #define BT_LOGF_AUX(log, ...) \ |
| 961 | BT_LOG_WRITE_AUX(log, BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__) |
| 962 | #define BT_LOGF_MEM(d, d_sz, ...) \ |
| 963 | BT_LOG_WRITE_MEM(BT_LOG_FATAL, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 964 | #define BT_LOGF_MEM_AUX(log, d, d_sz, ...) \ |
| 965 | BT_LOG_WRITE_MEM_AUX(log, BT_LOG_FATAL, _BT_LOG_TAG, d, d_sz, __VA_ARGS__) |
| 966 | #else |
| 967 | #define BT_LOGF(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 968 | #define BT_LOGF_ERRNO(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 969 | #define BT_LOGF_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 970 | #define BT_LOGF_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 971 | #define BT_LOGF_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__) |
| 972 | #endif |
| 973 | |
| 974 | #define BT_LOGT_STR(s) BT_LOGT("%s", (s)) |
| 975 | #define BT_LOGD_STR(s) BT_LOGD("%s", (s)) |
| 976 | #define BT_LOGI_STR(s) BT_LOGI("%s", (s)) |
| 977 | #define BT_LOGW_STR(s) BT_LOGW("%s", (s)) |
| 978 | #define BT_LOGE_STR(s) BT_LOGE("%s", (s)) |
| 979 | #define BT_LOGF_STR(s) BT_LOGF("%s", (s)) |
| 980 | |
| 981 | #ifdef __cplusplus |
| 982 | extern "C" { |
| 983 | #endif |
| 984 | |
| 985 | /* Output to standard error stream. Library uses it by default, though in few |
| 986 | * cases it could be necessary to specify it explicitly. For example, when |
| 987 | * bt_log library is compiled with BT_LOG_EXTERN_GLOBAL_OUTPUT, application must |
| 988 | * define and initialize global output variable: |
| 989 | * |
| 990 | * BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_OUT_STDERR}; |
| 991 | * |
| 992 | * Another example is when using custom output, stderr could be used as a |
| 993 | * fallback when custom output facility failed to initialize: |
| 994 | * |
| 995 | * bt_log_set_output_v(BT_LOG_OUT_STDERR); |
| 996 | */ |
| 997 | enum { BT_LOG_OUT_STDERR_MASK = BT_LOG_PUT_STD }; |
| 998 | |
| 999 | BT_HIDDEN |
| 1000 | void bt_log_out_stderr_callback(const bt_log_message *const msg, void *arg); |
| 1001 | #define BT_LOG_OUT_STDERR BT_LOG_OUT_STDERR_MASK, 0, bt_log_out_stderr_callback |
| 1002 | |
| 1003 | /* Predefined spec for stderr. Uses global format options (BT_LOG_GLOBAL_FORMAT) |
| 1004 | * and BT_LOG_OUT_STDERR. Could be used to force output to stderr for a |
| 1005 | * particular message. Example: |
| 1006 | * |
| 1007 | * f = fopen("foo.log", "w"); |
| 1008 | * if (!f) |
| 1009 | * BT_LOGE_AUX(BT_LOG_STDERR, "Failed to open log file"); |
| 1010 | */ |
| 1011 | #define BT_LOG_STDERR (&_bt_log_stderr_spec) |
| 1012 | |
| 1013 | /* |
| 1014 | * Returns the equivalent letter of the log level `level`. |
| 1015 | * |
| 1016 | * `level` must be a valid log level. |
| 1017 | */ |
| 1018 | static inline |
| 1019 | char bt_log_get_letter_from_level(int level) |
| 1020 | { |
| 1021 | char letter; |
| 1022 | |
| 1023 | switch (level) { |
| 1024 | case BT_LOG_TRACE: |
| 1025 | letter = 'T'; |
| 1026 | break; |
| 1027 | case BT_LOG_DEBUG: |
| 1028 | letter = 'D'; |
| 1029 | break; |
| 1030 | case BT_LOG_INFO: |
| 1031 | letter = 'I'; |
| 1032 | break; |
| 1033 | case BT_LOG_WARNING: |
| 1034 | letter = 'W'; |
| 1035 | break; |
| 1036 | case BT_LOG_ERROR: |
| 1037 | letter = 'E'; |
| 1038 | break; |
| 1039 | case BT_LOG_FATAL: |
| 1040 | letter = 'F'; |
| 1041 | break; |
| 1042 | case BT_LOG_NONE: |
| 1043 | letter = 'N'; |
| 1044 | break; |
| 1045 | default: |
| 1046 | abort(); |
| 1047 | } |
| 1048 | |
| 1049 | return letter; |
| 1050 | } |
| 1051 | |
| 1052 | /* |
| 1053 | * Returns the log level for the string `str`, or -1 if `str` is not a |
| 1054 | * valid log level string. |
| 1055 | */ |
| 1056 | static inline |
| 1057 | int bt_log_get_level_from_string(const char *str) |
| 1058 | { |
| 1059 | int level = -1; |
| 1060 | |
| 1061 | BT_ASSERT(str); |
| 1062 | |
| 1063 | if (strcmp(str, "TRACE") == 0 || |
| 1064 | strcmp(str, "T") == 0) { |
| 1065 | level = BT_LOG_TRACE; |
| 1066 | } else if (strcmp(str, "DEBUG") == 0 || |
| 1067 | strcmp(str, "D") == 0) { |
| 1068 | level = BT_LOG_DEBUG; |
| 1069 | } else if (strcmp(str, "INFO") == 0 || |
| 1070 | strcmp(str, "I") == 0) { |
| 1071 | level = BT_LOG_INFO; |
| 1072 | } else if (strcmp(str, "WARN") == 0 || |
| 1073 | strcmp(str, "WARNING") == 0 || |
| 1074 | strcmp(str, "W") == 0) { |
| 1075 | level = BT_LOG_WARNING; |
| 1076 | } else if (strcmp(str, "ERROR") == 0 || |
| 1077 | strcmp(str, "E") == 0) { |
| 1078 | level = BT_LOG_ERROR; |
| 1079 | } else if (strcmp(str, "FATAL") == 0 || |
| 1080 | strcmp(str, "F") == 0) { |
| 1081 | level = BT_LOG_FATAL; |
| 1082 | } else if (strcmp(str, "NONE") == 0 || |
| 1083 | strcmp(str, "N") == 0) { |
| 1084 | level = BT_LOG_NONE; |
| 1085 | } else { |
| 1086 | /* FIXME: Should we warn here? How? */ |
| 1087 | } |
| 1088 | |
| 1089 | return level; |
| 1090 | } |
| 1091 | |
| 1092 | /* |
| 1093 | * Returns the log level for the letter `letter`, or -1 if `letter` is |
| 1094 | * not a valid log level string. |
| 1095 | */ |
| 1096 | static inline |
| 1097 | int bt_log_get_level_from_letter(char letter) |
| 1098 | { |
| 1099 | char str[] = {letter, '\0'}; |
| 1100 | |
| 1101 | return bt_log_get_level_from_string(str); |
| 1102 | } |
| 1103 | |
| 1104 | static inline |
| 1105 | int bt_log_get_level_from_env(const char *var) |
| 1106 | { |
| 1107 | const char *varval = getenv(var); |
| 1108 | int level = BT_LOG_NONE; |
| 1109 | |
| 1110 | if (!varval) { |
| 1111 | goto end; |
| 1112 | } |
| 1113 | |
| 1114 | level = bt_log_get_level_from_string(varval); |
| 1115 | if (level < 0) { |
| 1116 | /* FIXME: Should we warn here? How? */ |
| 1117 | level = BT_LOG_NONE; |
| 1118 | } |
| 1119 | |
| 1120 | end: |
| 1121 | return level; |
| 1122 | } |
| 1123 | |
| 1124 | #define BT_LOG_LEVEL_EXTERN_SYMBOL(_level_sym) \ |
| 1125 | extern int _level_sym |
| 1126 | |
| 1127 | #define BT_LOG_INIT_LOG_LEVEL(_level_sym, _env_var) \ |
| 1128 | BT_HIDDEN int _level_sym = BT_LOG_NONE; \ |
| 1129 | static \ |
| 1130 | void __attribute__((constructor)) _bt_log_level_ctor(void) \ |
| 1131 | { \ |
| 1132 | _level_sym = bt_log_get_level_from_env(_env_var); \ |
| 1133 | } |
| 1134 | |
| 1135 | #define BT_LOG_SUPPORTED |
| 1136 | |
| 1137 | #ifdef __cplusplus |
| 1138 | } |
| 1139 | #endif |
| 1140 | |
| 1141 | #endif /* BABELTRACE_LOGGING_INTERNAL_H */ |