1/* @TAG(CUSTOM) */ 2/* zf log taken from: https://github.com/wonder-mice/zf_log 3 * 4 * "Software source code can not be printed on paper and sticked to a cat." 5 */ 6 7#pragma once 8 9#include <utils/attribute.h> 10 11/* To detect incompatible changes you can define ZF_LOG_VERSION_REQUIRED to 12 * the current value of ZF_LOG_VERSION before including this file (or via 13 * compiler command line): 14 * 15 * #define ZF_LOG_VERSION_REQUIRED 1 16 * #include <zf_log.h> 17 * 18 * In that case compilation will fail when included file has incompatible 19 * version. 20 */ 21#define ZF_LOG_VERSION 1 22#if defined(ZF_LOG_VERSION_REQUIRED) 23 #if ZF_LOG_VERSION_REQUIRED != ZF_LOG_VERSION 24 #error different zf_log version required 25 #endif 26#endif 27 28/* Log level guideline: 29 * - ZF_LOG_FATAL - happened something impossible and absolutely unexpected. 30 * Process can't continue and must be terminated. In other words, semantic is 31 * close to assert(). zf_log will call abort() after printing the log message. 32 * Example: division by zero, unexpected modifications from other thread. 33 * - ZF_LOG_ERROR - happened something impossible and absolutely unexpected, but 34 * process is able to recover and continue execution. 35 * Example: out of memory (could also be FATAL if not handled properly). 36 * - ZF_LOG_WARN - happened something that *usually* should not happen and 37 * significantly changes application behavior for some period of time. 38 * Example: configuration file not found, auth error. 39 * - ZF_LOG_INFO - happened significant life cycle event or major state 40 * transition. 41 * Example: app started, user logged in. 42 * - ZF_LOG_DEBUG - minimal set of events that could help to reconstruct the 43 * execution path. 44 * - ZF_LOG_VERBOSE - all other events. 45 * 46 * Ideally, log file of debugged, well tested, production ready application 47 * should be empty (no messages with level ZF_LOG_INFO or higher) or very small. 48 */ 49#define ZF_LOG_VERBOSE 1 50#define ZF_LOG_DEBUG 2 51#define ZF_LOG_INFO 3 52#define ZF_LOG_WARN 4 53#define ZF_LOG_ERROR 5 54#define ZF_LOG_FATAL 0xFFFF 55#define ZF_LOG_NONE 0xFFFF 56 57/* Log level configuration: 58 * - ZF_LOG_DEF_LEVEL - defines current log level. Only messages with that level 59 * and higher will be logged (if ZF_LOG_LEVEL is undefined). 60 * - ZF_LOG_LEVEL - overrides current log level. Only messages with that level 61 * and higher will be logged. 62 * 63 * Current log level is a compile time check and has no runtime overhead. 64 * 65 * Common pattern is to define ZF_LOG_DEF_LEVEL in the build script (e.g. 66 * Makefile, CMakeLists.txt) for the entire project/target: 67 * 68 * CC_ARGS := -DZF_LOG_DEF_LEVEL=ZF_LOG_WARN 69 * 70 * And when necessary override it with ZF_LOG_LEVEL in .c/.cpp files (before 71 * including zf_log.h): 72 * 73 * #define ZF_LOG_LEVEL ZF_LOG_VERBOSE 74 * #include <zf_log.h> 75 * 76 * Defining either ZF_LOG_DEF_LEVEL or ZF_LOG_LEVEL in header file is usually 77 * undesired and produces weird results. 78 * 79 * If both ZF_LOG_DEF_LEVEL and ZF_LOG_LEVEL are undefined, then ZF_LOG_INFO 80 * will be used for release builds (NDEBUG is defined) and ZF_LOG_DEBUG 81 * otherwise. 82 * 83 * When log message has level bellow current log level it will be compiled out 84 * and its arguments will NOT be evaluated (no "unused variable" warning will be 85 * generated for variables that are only used in compiled out log messages). 86 */ 87#if defined(ZF_LOG_LEVEL) 88 #define _ZF_LOG_LEVEL ZF_LOG_LEVEL 89#elif defined(ZF_LOG_DEF_LEVEL) 90 #define _ZF_LOG_LEVEL ZF_LOG_DEF_LEVEL 91#else 92 #ifdef NDEBUG 93 #define _ZF_LOG_LEVEL ZF_LOG_INFO 94 #else 95 #define _ZF_LOG_LEVEL ZF_LOG_DEBUG 96 #endif 97#endif 98 99/* Log tag configuration: 100 * - ZF_LOG_DEF_TAG - defines default log tag. 101 * - ZF_LOG_TAG - overrides default log tag. 102 * 103 * When defined, value must be a string constant (in double quotes): 104 * 105 * #define ZF_LOG_TAG "MAIN" 106 * #include <zf_log.h> 107 * 108 * Defining either ZF_LOG_DEF_TAG or ZF_LOG_TAG in header files usually 109 * undesired and produces weird results. 110 * 111 * If both ZF_LOG_DEF_TAG and ZF_LOG_TAG are undefined no tag will be added to 112 * the log message. 113 */ 114#if defined(ZF_LOG_TAG) 115 #define _ZF_LOG_TAG ZF_LOG_TAG 116#elif defined(ZF_LOG_DEF_TAG) 117 #define _ZF_LOG_TAG ZF_LOG_DEF_TAG 118#else 119 #define _ZF_LOG_TAG 0 120#endif 121 122/* When defined, all produced linker symbols will be prefixed with the specified 123 * value. That allows to use zf_log privately in another library without 124 * exposing zf_log symbols in their original form (so library will not have 125 * externaly visible dependency on zf_log). Value must be without quotes: 126 * 127 * CC_ARGS := -DZF_LOG_LIBRARY_PREFIX=my_lib 128 */ 129#ifdef ZF_LOG_LIBRARY_PREFIX 130 #define _ZF_LOG_DECOR__(prefix, name) prefix ## name 131 #define _ZF_LOG_DECOR_(prefix, name) _ZF_LOG_DECOR__(prefix, name) 132 #define _ZF_LOG_DECOR(name) _ZF_LOG_DECOR_(ZF_LOG_LIBRARY_PREFIX, name) 133 134 #define zf_log_set_tag_prefix _ZF_LOG_DECOR(zf_log_set_tag_prefix) 135 #define zf_log_set_mem_width _ZF_LOG_DECOR(zf_log_set_mem_width) 136 #define zf_log_set_output_level _ZF_LOG_DECOR(zf_log_set_output_level) 137 #define zf_log_set_output_callback _ZF_LOG_DECOR(zf_log_set_output_callback) 138 #define _zf_log_output_lvl _ZF_LOG_DECOR(_zf_log_output_lvl) 139 #define _zf_log_write_d _ZF_LOG_DECOR(_zf_log_write_d) 140 #define _zf_log_write _ZF_LOG_DECOR(_zf_log_write) 141 #define _zf_log_write_mem_d _ZF_LOG_DECOR(_zf_log_write_mem_d) 142 #define _zf_log_write_mem _ZF_LOG_DECOR(_zf_log_write_mem) 143#endif 144 145/* Runtime configuration */ 146#ifdef __cplusplus 147extern "C" { 148#endif 149 150/* Set tag prefix. Prefix will be separated from the tag with dot ('.'). 151 * Use 0 or empty string to disable (default). Common use is to set it to 152 * the process (or target) name (e.g. to separate client and server process). 153 */ 154void zf_log_set_tag_prefix(const char *const prefix); 155 156/* Set number of bytes per log line in memory dump. 157 */ 158void zf_log_set_mem_width(const unsigned w); 159 160/* Set output log level. Output log level is a run time check and has low 161 * overhead of compare operation and conditional jump. When the log message has 162 * level bellow output log level it will not be logged and its arguments will 163 * NOT be evaluated. 164 * 165 * Since all messages that are below current log level are compiled out, 166 * only messages that are on or above the current log level are affected by the 167 * output log level check. 168 * 169 * Output log level can be changed at any time during program execution. 170 */ 171void zf_log_set_output_level(const int lvl); 172 173typedef struct zf_log_output_ctx 174{ 175 int lvl; 176 const char *tag; 177 char *buf; /* Buffer start */ 178 char *e; /* Buffer end (last position where EOL with 0 could be written) */ 179 char *p; /* Buffer content end (append position) */ 180 char *tag_b; /* Prefixed tag start */ 181 char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */ 182 char *msg_b; /* Message start (expanded format string) */ 183} 184zf_log_output_ctx; 185 186typedef void (*zf_log_output_cb)(zf_log_output_ctx *ctx); 187 188/* Set output callback function. It will be called for each log line allowed 189 * by both current log level and output log level. Callback function is allowed 190 * to modify content of the buffers pointed by the ctx, but it's not allowed to 191 * modify buffer pointers and other fields. 192 */ 193void zf_log_set_output_callback(const zf_log_output_cb cb); 194 195#ifdef __cplusplus 196} 197#endif 198 199/* Checking current log level at compile time (ignoring output log level). 200 * For example: 201 * 202 * #if ZF_LOG_ALLOW_DEBUG 203 * const char *const g_enum_strings[] = { 204 * "enum_value_0", "enum_value_1", "enum_value_2" 205 * }; 206 * #endif 207 * // ... 208 * #if ZF_LOG_ALLOW_DEBUG 209 * ZF_LOGD("enum value: %s", g_enum_strings[v]); 210 * #endif 211 */ 212#define ZF_LOG_ALLOW(lvl) ((lvl) >= _ZF_LOG_LEVEL) 213#define ZF_LOG_ALLOW_VERBOSE ZF_LOG_ALLOW(ZF_LOG_VERBOSE) 214#define ZF_LOG_ALLOW_DEBUG ZF_LOG_ALLOW(ZF_LOG_DEBUG) 215#define ZF_LOG_ALLOW_INFO ZF_LOG_ALLOW(ZF_LOG_INFO) 216#define ZF_LOG_ALLOW_WARN ZF_LOG_ALLOW(ZF_LOG_WARN) 217#define ZF_LOG_ALLOW_ERROR ZF_LOG_ALLOW(ZF_LOG_ERROR) 218#define ZF_LOG_ALLOW_FATAL ZF_LOG_ALLOW(ZF_LOG_FATAL) 219 220/* Checking output log level at run time (taking into account current log 221 * level). For example: 222 * 223 * if (ZF_LOG_OUTPUT_DEBUG) 224 * { 225 * char hash[65]; 226 * sha256(data_ptr, data_sz, hash); 227 * ZF_LOGD("data: len=%u, sha256=%s", data_sz, hash); 228 * } 229 */ 230#define ZF_LOG_OUTPUT(lvl) \ 231 (ZF_LOG_ALLOW((lvl)) && (lvl) >= _zf_log_output_lvl) 232#define ZF_LOG_OUTPUT_VERBOSE ZF_LOG_OUTPUT(ZF_LOG_VERBOSE) 233#define ZF_LOG_OUTPUT_DEBUG ZF_LOG_OUTPUT(ZF_LOG_DEBUG) 234#define ZF_LOG_OUTPUT_INFO ZF_LOG_OUTPUT(ZF_LOG_INFO) 235#define ZF_LOG_OUTPUT_WARN ZF_LOG_OUTPUT(ZF_LOG_WARN) 236#define ZF_LOG_OUTPUT_ERROR ZF_LOG_OUTPUT(ZF_LOG_ERROR) 237#define ZF_LOG_OUTPUT_FATAL ZF_LOG_OUTPUT(ZF_LOG_FATAL) 238 239#define _ZF_LOG_PRINTFLIKE(a, b) FORMAT(printf, a, b) 240 241#ifdef __cplusplus 242extern "C" { 243#endif 244 245extern int _zf_log_output_lvl; 246 247void _zf_log_write_d(const char *const func, 248 const char *const file, const unsigned line, 249 const int lvl, const char *const tag, 250 const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(6, 7); 251void _zf_log_write(const int lvl, const char *const tag, 252 const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(3, 4); 253 254void _zf_log_write_mem_d(const char *const func, 255 const char *const file, const unsigned line, 256 const int lvl, const char *const tag, 257 const void *const d, const unsigned d_sz, 258 const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(8, 9); 259void _zf_log_write_mem(const int lvl, const char *const tag, 260 const void *const d, const unsigned d_sz, 261 const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(5, 6); 262#ifdef __cplusplus 263} 264#endif 265 266/* Message logging macros: 267 * - ZF_LOGV("format string", args, ...) 268 * - ZF_LOGD("format string", args, ...) 269 * - ZF_LOGI("format string", args, ...) 270 * - ZF_LOGW("format string", args, ...) 271 * - ZF_LOGF("format string", args, ...) 272 * 273 * Memory logging macros: 274 * - ZF_LOGV_MEM(data_ptr, data_sz, "format string", args, ...) 275 * - ZF_LOGD_MEM(data_ptr, data_sz, "format string", args, ...) 276 * - ZF_LOGI_MEM(data_ptr, data_sz, "format string", args, ...) 277 * - ZF_LOGW_MEM(data_ptr, data_sz, "format string", args, ...) 278 * - ZF_LOGF_MEM(data_ptr, data_sz, "format string", args, ...) 279 * 280 * Format string follows printf() conventions. Both data_ptr and data_sz could 281 * be 0. 282 */ 283#ifdef NDEBUG 284 #define _ZF_LOG_IMP(lvl, tag, ...) \ 285 do { \ 286 if (ZF_LOG_OUTPUT(lvl)) \ 287 _zf_log_write(lvl, tag, __VA_ARGS__); \ 288 } while (0) 289 #define _ZF_LOG_MEM_IMP(lvl, tag, d, d_sz, ...) \ 290 do { \ 291 if (ZF_LOG_OUTPUT(lvl)) \ 292 _zf_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \ 293 } while (0) 294#else 295 #define _ZF_LOG_IMP(lvl, tag, ...) \ 296 do { \ 297 if (ZF_LOG_OUTPUT(lvl)) \ 298 _zf_log_write_d(__FUNCTION__, __FILE__, __LINE__, \ 299 lvl, tag, __VA_ARGS__); \ 300 } while (0) 301 #define _ZF_LOG_MEM_IMP(lvl, tag, d, d_sz, ...) \ 302 do { \ 303 if (ZF_LOG_OUTPUT(lvl)) \ 304 _zf_log_write_mem_d(__FUNCTION__, __FILE__, __LINE__, \ 305 lvl, tag, d, d_sz, __VA_ARGS__); \ 306 } while (0) 307#endif 308 309static inline void _zf_log_unused(const int dummy, ...) {(void)dummy;} 310 311#define _ZF_LOG_UNUSED(...) \ 312 do { if (0) _zf_log_unused(0, __VA_ARGS__); } while (0) 313 314#if ZF_LOG_ALLOW_VERBOSE 315 #define ZF_LOGV(...) \ 316 _ZF_LOG_IMP(ZF_LOG_VERBOSE, _ZF_LOG_TAG, __VA_ARGS__) 317 #define ZF_LOGV_MEM(...) \ 318 _ZF_LOG_MEM_IMP(ZF_LOG_VERBOSE, _ZF_LOG_TAG, __VA_ARGS__) 319#else 320 #define ZF_LOGV(...) _ZF_LOG_UNUSED(__VA_ARGS__) 321 #define ZF_LOGV_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__) 322#endif 323 324#if ZF_LOG_ALLOW_DEBUG 325 #define ZF_LOGD(...) \ 326 _ZF_LOG_IMP(ZF_LOG_DEBUG, _ZF_LOG_TAG, __VA_ARGS__) 327 #define ZF_LOGD_MEM(...) \ 328 _ZF_LOG_MEM_IMP(ZF_LOG_DEBUG, _ZF_LOG_TAG, __VA_ARGS__) 329#else 330 #define ZF_LOGD(...) _ZF_LOG_UNUSED(__VA_ARGS__) 331 #define ZF_LOGD_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__) 332#endif 333 334#if ZF_LOG_ALLOW_INFO 335 #define ZF_LOGI(...) \ 336 _ZF_LOG_IMP(ZF_LOG_INFO, _ZF_LOG_TAG, __VA_ARGS__) 337 #define ZF_LOGI_MEM(...) \ 338 _ZF_LOG_MEM_IMP(ZF_LOG_INFO, _ZF_LOG_TAG, __VA_ARGS__) 339#else 340 #define ZF_LOGI(...) _ZF_LOG_UNUSED(__VA_ARGS__) 341 #define ZF_LOGI_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__) 342#endif 343 344#if ZF_LOG_ALLOW_WARN 345 #define ZF_LOGW(...) \ 346 _ZF_LOG_IMP(ZF_LOG_WARN, _ZF_LOG_TAG, __VA_ARGS__) 347 #define ZF_LOGW_MEM(...) \ 348 _ZF_LOG_MEM_IMP(ZF_LOG_WARN, _ZF_LOG_TAG, __VA_ARGS__) 349#else 350 #define ZF_LOGW(...) _ZF_LOG_UNUSED(__VA_ARGS__) 351 #define ZF_LOGW_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__) 352#endif 353 354#if ZF_LOG_ALLOW_ERROR 355 #define ZF_LOGE(...) \ 356 _ZF_LOG_IMP(ZF_LOG_ERROR, _ZF_LOG_TAG, __VA_ARGS__) 357 #define ZF_LOGE_MEM(...) \ 358 _ZF_LOG_MEM_IMP(ZF_LOG_ERROR, _ZF_LOG_TAG, __VA_ARGS__) 359#else 360 #define ZF_LOGE(...) _ZF_LOG_UNUSED(__VA_ARGS__) 361 #define ZF_LOGE_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__) 362#endif 363 364#if ZF_LOG_ALLOW_FATAL 365 #define ZF_LOGF(...) do { \ 366 _ZF_LOG_IMP(ZF_LOG_FATAL, _ZF_LOG_TAG, __VA_ARGS__); UNREACHABLE();\ 367 } while (0) 368 #define ZF_LOGF_MEM(...) do { \ 369 _ZF_LOG_MEM_IMP(ZF_LOG_FATAL, _ZF_LOG_TAG, __VA_ARGS__); UNREACHABLE();\ 370 } while (0) 371#else 372 #define ZF_LOGF(...) _ZF_LOG_UNUSED(__VA_ARGS__) 373 #define ZF_LOGF_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__) 374#endif 375