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