2 * This is zf_log.c, modified with Babeltrace prefixes.
3 * See <https://github.com/wonder-mice/zf_log/>.
7 #include <babeltrace/babeltrace-internal.h>
8 #include <babeltrace/common-internal.h>
12 extern unsigned long pthread_getsequence_np(pthread_t
*);
15 /* When defined, Android log (android/log.h) will be used by default instead of
16 * stderr (ignored on non-Android platforms). Date, time, pid and tid (context)
17 * will be provided by Android log. Android log features will be used to output
20 #ifdef BT_LOG_USE_ANDROID_LOG
21 #undef BT_LOG_USE_ANDROID_LOG
22 #if defined(__ANDROID__)
23 #define BT_LOG_USE_ANDROID_LOG 1
25 #define BT_LOG_USE_ANDROID_LOG 0
28 #define BT_LOG_USE_ANDROID_LOG 0
30 /* When defined, NSLog (uses Apple System Log) will be used instead of stderr
31 * (ignored on non-Apple platforms). Date, time, pid and tid (context) will be
32 * provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on
33 * non-public CFLog() function. Both use Apple System Log internally, but it's
34 * easier to call CFLog() from C than NSLog(). Current implementation doesn't
35 * support "%@" format specifier.
37 #ifdef BT_LOG_USE_NSLOG
38 #undef BT_LOG_USE_NSLOG
39 #if defined(__APPLE__) && defined(__MACH__)
40 #define BT_LOG_USE_NSLOG 1
42 #define BT_LOG_USE_NSLOG 0
45 #define BT_LOG_USE_NSLOG 0
47 /* When defined, OutputDebugString() will be used instead of stderr (ignored on
48 * non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with
51 #ifdef BT_LOG_USE_DEBUGSTRING
52 #undef BT_LOG_USE_DEBUGSTRING
53 #if defined(_WIN32) || defined(_WIN64)
54 #define BT_LOG_USE_DEBUGSTRING 1
56 #define BT_LOG_USE_DEBUGSTRING 0
59 #define BT_LOG_USE_DEBUGSTRING 0
61 /* When defined, bt_log library will not contain definition of tag prefix
62 * variable. In that case it must be defined elsewhere using
63 * BT_LOG_DEFINE_TAG_PREFIX macro, for example:
65 * BT_LOG_DEFINE_TAG_PREFIX = "ProcessName";
67 * This allows to specify custom value for static initialization and avoid
68 * overhead of setting this value in runtime.
70 #ifdef BT_LOG_EXTERN_TAG_PREFIX
71 #undef BT_LOG_EXTERN_TAG_PREFIX
72 #define BT_LOG_EXTERN_TAG_PREFIX 1
74 #define BT_LOG_EXTERN_TAG_PREFIX 0
76 /* When defined, bt_log library will not contain definition of global format
77 * variable. In that case it must be defined elsewhere using
78 * BT_LOG_DEFINE_GLOBAL_FORMAT macro, for example:
80 * BT_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH};
82 * This allows to specify custom value for static initialization and avoid
83 * overhead of setting this value in runtime.
85 #ifdef BT_LOG_EXTERN_GLOBAL_FORMAT
86 #undef BT_LOG_EXTERN_GLOBAL_FORMAT
87 #define BT_LOG_EXTERN_GLOBAL_FORMAT 1
89 #define BT_LOG_EXTERN_GLOBAL_FORMAT 0
91 /* When defined, bt_log library will not contain definition of global output
92 * variable. In that case it must be defined elsewhere using
93 * BT_LOG_DEFINE_GLOBAL_OUTPUT macro, for example:
95 * BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_PUT_STD, custom_output_callback};
97 * This allows to specify custom value for static initialization and avoid
98 * overhead of setting this value in runtime.
100 #ifdef BT_LOG_EXTERN_GLOBAL_OUTPUT
101 #undef BT_LOG_EXTERN_GLOBAL_OUTPUT
102 #define BT_LOG_EXTERN_GLOBAL_OUTPUT 1
104 #define BT_LOG_EXTERN_GLOBAL_OUTPUT 0
106 /* When defined, bt_log library will not contain definition of global output
107 * level variable. In that case it must be defined elsewhere using
108 * BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example:
110 * BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = BT_LOG_WARN;
112 * This allows to specify custom value for static initialization and avoid
113 * overhead of setting this value in runtime.
115 #ifdef BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
116 #undef BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
117 #define BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1
119 #define BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0
121 /* When defined, implementation will prefer smaller code size over speed.
122 * Very rough estimate is that code will be up to 2x smaller and up to 2x
123 * slower. Disabled by default.
125 #ifdef BT_LOG_OPTIMIZE_SIZE
126 #undef BT_LOG_OPTIMIZE_SIZE
127 #define BT_LOG_OPTIMIZE_SIZE 1
129 #define BT_LOG_OPTIMIZE_SIZE 0
131 /* Size of the log line buffer. The buffer is allocated on stack. It limits
132 * maximum length of a log line.
134 #ifndef BT_LOG_BUF_SZ
135 #define BT_LOG_BUF_SZ 512
137 /* Default number of bytes in one line of memory output. For large values
138 * BT_LOG_BUF_SZ also must be increased.
140 #ifndef BT_LOG_MEM_WIDTH
141 #define BT_LOG_MEM_WIDTH 32
143 /* String to put in the end of each log line (can be empty). Its value used by
144 * stderr output callback. Its size used as a default value for BT_LOG_EOL_SZ.
147 #define BT_LOG_EOL "\n"
149 /* Default delimiter that separates parts of log message. Can NOT contain '%'
152 * Log message format specifications can override (or ignore) this value. For
153 * more details see BT_LOG_MESSAGE_CTX_FORMAT, BT_LOG_MESSAGE_SRC_FORMAT and
154 * BT_LOG_MESSAGE_TAG_FORMAT.
156 #ifndef BT_LOG_DEF_DELIMITER
157 #define BT_LOG_DEF_DELIMITER " "
159 /* Specifies log message context format. Log message context includes date,
160 * time, process id, thread id and message's log level. Custom information can
161 * be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,
162 * MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements),
163 * F_UINT(width, value).
165 * Must be defined as a tuple, for example:
167 * #define BT_LOG_MESSAGE_CTX_FORMAT (YEAR, S("."), MONTH, S("."), DAY, S(" > "))
169 * In that case, resulting log message will be:
171 * 2016.12.22 > TAG function@filename.c:line Message text
173 * Note, that tag, source location and message text are not impacted by
174 * this setting. See BT_LOG_MESSAGE_TAG_FORMAT and BT_LOG_MESSAGE_SRC_FORMAT.
176 * If message context must be visually separated from the rest of the message,
177 * it must be reflected in context format (notice trailing S(" > ") in the
180 * S(str) adds constant string str. String can NOT contain '%' or '\0'.
182 * F_INIT(statements) adds initialization statement(s) that will be evaluated
183 * once for each log message. All statements are evaluated in specified order.
184 * Several F_INIT() fields can be used in every log message format
185 * specification. Fields, like F_UINT(width, value), are allowed to use results
186 * of initialization statements. If statement introduces variables (or other
187 * names, like structures) they must be prefixed with "f_". Statements must be
188 * enclosed into additional "()". Example:
190 * #define BT_LOG_MESSAGE_CTX_FORMAT \
191 * (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \
192 * YEAR, S("."), MONTH, S("."), DAY, S(" "), \
193 * F_UINT(5, f_ru.ru_nsignals), \
196 * F_UINT(width, value) adds unsigned integer value extended with up to width
197 * spaces (for alignment purposes). Value can be any expression that evaluates
198 * to unsigned integer. If expression contains non-standard functions, they
199 * must be declared with F_INIT(). Example:
201 * #define BT_LOG_MESSAGE_CTX_FORMAT \
202 * (YEAR, S("."), MONTH, S("."), DAY, S(" "), \
203 * F_INIT(( unsigned tickcount(); )), \
204 * F_UINT(5, tickcount()), \
207 * Other log message format specifications follow same rules, but have a
208 * different set of supported fields.
210 #ifndef BT_LOG_MESSAGE_CTX_FORMAT
211 #define BT_LOG_MESSAGE_CTX_FORMAT \
212 (MONTH, S("-"), DAY, S(BT_LOG_DEF_DELIMITER), \
213 HOUR, S(":"), MINUTE, S(":"), SECOND, S("."), MILLISECOND, S(BT_LOG_DEF_DELIMITER), \
214 PID, S(BT_LOG_DEF_DELIMITER), TID, S(BT_LOG_DEF_DELIMITER), \
215 LEVEL, S(BT_LOG_DEF_DELIMITER))
219 /* Specifies log message tag format. It includes tag prefix and tag. Custom
220 * information can be added as well. Supported fields:
221 * TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements),
222 * F_UINT(width, value).
224 * TAG(prefix_delimiter, tag_delimiter) adds following string to log message:
226 * PREFIX<prefix_delimiter>TAG<tag_delimiter>
228 * Prefix delimiter will be used only when prefix is not empty. Tag delimiter
229 * will be used only when prefixed tag is not empty. Example:
231 * #define BT_LOG_TAG_FORMAT (S("["), TAG(".", ""), S("] "))
233 * See BT_LOG_MESSAGE_CTX_FORMAT for details.
235 #ifndef BT_LOG_MESSAGE_TAG_FORMAT
236 #define BT_LOG_MESSAGE_TAG_FORMAT \
237 (TAG(".", BT_LOG_DEF_DELIMITER))
239 /* Specifies log message source location format. It includes function name,
240 * file name and file line. Custom information can be added as well. Supported
241 * fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements),
242 * F_UINT(width, value).
244 * See BT_LOG_MESSAGE_CTX_FORMAT for details.
246 #ifndef BT_LOG_MESSAGE_SRC_FORMAT
247 #define BT_LOG_MESSAGE_SRC_FORMAT \
248 (FUNCTION, S("@"), FILENAME, S(":"), FILELINE, S(BT_LOG_DEF_DELIMITER))
250 /* Fields that can be used in log message format specifications (see above).
251 * Mentioning them here explicitly, so we know that nobody else defined them
252 * before us. See BT_LOG_MESSAGE_CTX_FORMAT for details.
257 #define MINUTE MINUTE
258 #define SECOND SECOND
259 #define MILLISECOND MILLISECOND
263 #define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim)
264 #define FUNCTION FUNCTION
265 #define FILENAME FILENAME
266 #define FILELINE FILELINE
267 #define S(str) S(str)
268 #define F_INIT(statements) F_INIT(statements)
269 #define F_UINT(width, value) F_UINT(width, value)
270 /* Number of bytes to reserve for EOL in the log line buffer (must be >0).
271 * Must be larger than or equal to length of BT_LOG_EOL with terminating null.
273 #ifndef BT_LOG_EOL_SZ
274 #define BT_LOG_EOL_SZ sizeof(BT_LOG_EOL)
276 /* Compile instrumented version of the library to facilitate unit testing.
278 #ifndef BT_LOG_INSTRUMENTED
279 #define BT_LOG_INSTRUMENTED 0
282 #if defined(__linux__)
283 #if !defined(__ANDROID__) && !defined(_GNU_SOURCE)
287 #if defined(__MINGW32__)
288 #ifdef __STRICT_ANSI__
289 #undef __STRICT_ANSI__
301 #define BT_LOG_OUTPUT_LEVEL dummy
303 #include <babeltrace/logging-internal.h>
304 #include <babeltrace/logging.h>
306 #if defined(_WIN32) || defined(_WIN64)
310 #include <sys/time.h>
311 #if defined(__linux__)
312 #include <linux/limits.h>
314 #include <sys/syslimits.h>
318 #if defined(__linux__)
319 #include <sys/prctl.h>
320 #include <sys/types.h>
321 #if !defined(__ANDROID__)
322 #include <sys/syscall.h>
325 #if defined(__MACH__)
329 #define INLINE _BT_LOG_INLINE
330 #define VAR_UNUSED(var) (void)var
331 #define RETVAL_UNUSED(expr) do { while(expr) break; } while(0)
332 #define STATIC_ASSERT(name, cond) \
333 typedef char assert_##name[(cond)? 1: -1]
334 #define ASSERT_UNREACHABLE(why) assert(!sizeof(why))
336 #define _countof(xs) (sizeof(xs) / sizeof((xs)[0]))
339 #if BT_LOG_INSTRUMENTED
340 #define INSTRUMENTED_CONST
342 #define INSTRUMENTED_CONST const
345 #define _PP_PASTE_2(a, b) a ## b
346 #define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b)
348 #define _PP_PASTE_3(a, b, c) a ## b ## c
349 #define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c)
351 /* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__
352 * as a single token and requires additional expansion to realize that it's
353 * actually a list. If not for it, there would be no need in this extra
357 #define _PP_NARGS_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,...) _24
358 #define _PP_NARGS(...) _PP_ID(_PP_NARGS_N(__VA_ARGS__,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))
360 /* There is a more efficient way to implement this, but it requires
361 * working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't
364 #define _PP_HEAD__(x, ...) x
365 #define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~))
366 #define _PP_HEAD(xs) _PP_HEAD_ xs
367 #define _PP_TAIL_(x, ...) (__VA_ARGS__)
368 #define _PP_TAIL(xs) _PP_TAIL_ xs
369 #define _PP_UNTUPLE_(...) __VA_ARGS__
370 #define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs
372 /* Apply function macro to each element in tuple. Output is not
373 * enforced to be a tuple.
375 #define _PP_MAP_1(f, xs) f(_PP_HEAD(xs))
376 #define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs))
377 #define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs))
378 #define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs))
379 #define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs))
380 #define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs))
381 #define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs))
382 #define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs))
383 #define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs))
384 #define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs))
385 #define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs))
386 #define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs))
387 #define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs))
388 #define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs))
389 #define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs))
390 #define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs))
391 #define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs))
392 #define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs))
393 #define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs))
394 #define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs))
395 #define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs))
396 #define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs))
397 #define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs))
398 #define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs))
399 #define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs) (f, xs)
401 /* Apply function macro to each element in tuple in reverse order.
402 * Output is not enforced to be a tuple.
404 #define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs))
405 #define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
406 #define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
407 #define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
408 #define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
409 #define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
410 #define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
411 #define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
412 #define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
413 #define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
414 #define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
415 #define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
416 #define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
417 #define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
418 #define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
419 #define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
420 #define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
421 #define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
422 #define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
423 #define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
424 #define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
425 #define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
426 #define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
427 #define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
428 #define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs) (f, xs)
430 /* Used to implement _BT_LOG_MESSAGE_FORMAT_CONTAINS() macro. All possible
431 * fields must be mentioned here. Not counting F_INIT() here because it's
432 * somewhat special and is handled spearatly (at least for now).
434 #define _BT_LOG_MESSAGE_FORMAT_MASK__ (0<<0)
435 #define _BT_LOG_MESSAGE_FORMAT_MASK__YEAR (1<<1)
436 #define _BT_LOG_MESSAGE_FORMAT_MASK__MONTH (1<<2)
437 #define _BT_LOG_MESSAGE_FORMAT_MASK__DAY (1<<3)
438 #define _BT_LOG_MESSAGE_FORMAT_MASK__HOUR (1<<4)
439 #define _BT_LOG_MESSAGE_FORMAT_MASK__MINUTE (1<<5)
440 #define _BT_LOG_MESSAGE_FORMAT_MASK__SECOND (1<<6)
441 #define _BT_LOG_MESSAGE_FORMAT_MASK__MILLISECOND (1<<7)
442 #define _BT_LOG_MESSAGE_FORMAT_MASK__PID (1<<8)
443 #define _BT_LOG_MESSAGE_FORMAT_MASK__TID (1<<9)
444 #define _BT_LOG_MESSAGE_FORMAT_MASK__LEVEL (1<<10)
445 #define _BT_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts) (1<<11)
446 #define _BT_LOG_MESSAGE_FORMAT_MASK__FUNCTION (1<<12)
447 #define _BT_LOG_MESSAGE_FORMAT_MASK__FILENAME (1<<13)
448 #define _BT_LOG_MESSAGE_FORMAT_MASK__FILELINE (1<<14)
449 #define _BT_LOG_MESSAGE_FORMAT_MASK__S(s) (1<<15)
450 #define _BT_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0<<16)
451 #define _BT_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1<<17)
452 #define _BT_LOG_MESSAGE_FORMAT_MASK(field) \
453 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_MASK_, _, field)
455 /* Logical "or" of masks of fields used in specified format specification.
457 #define _BT_LOG_MESSAGE_FORMAT_FIELDS(format) \
458 (0 _PP_MAP(| _BT_LOG_MESSAGE_FORMAT_MASK, format))
460 /* Expands to expressions that evaluates to true if field is used in
461 * specified format specification. Example:
463 * #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT, BT_LOG_MESSAGE_CTX_FORMAT)
467 #define _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, format) \
468 (_BT_LOG_MESSAGE_FORMAT_MASK(field) & _BT_LOG_MESSAGE_FORMAT_FIELDS(format))
470 /* Same, but checks all supported format specifications.
472 #define _BT_LOG_MESSAGE_FORMAT_FIELD_USED(field) \
473 (_BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_CTX_FORMAT) || \
474 _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_TAG_FORMAT) || \
475 _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_SRC_FORMAT))
477 #define _BT_LOG_MESSAGE_FORMAT_DATETIME_USED \
478 (_BT_LOG_MESSAGE_FORMAT_CONTAINS(YEAR, BT_LOG_MESSAGE_CTX_FORMAT) || \
479 _BT_LOG_MESSAGE_FORMAT_CONTAINS(MONTH, BT_LOG_MESSAGE_CTX_FORMAT) || \
480 _BT_LOG_MESSAGE_FORMAT_CONTAINS(DAY, BT_LOG_MESSAGE_CTX_FORMAT) || \
481 _BT_LOG_MESSAGE_FORMAT_CONTAINS(HOUR, BT_LOG_MESSAGE_CTX_FORMAT) || \
482 _BT_LOG_MESSAGE_FORMAT_CONTAINS(MINUTE, BT_LOG_MESSAGE_CTX_FORMAT) || \
483 _BT_LOG_MESSAGE_FORMAT_CONTAINS(SECOND, BT_LOG_MESSAGE_CTX_FORMAT) || \
484 _BT_LOG_MESSAGE_FORMAT_CONTAINS(MILLISECOND, BT_LOG_MESSAGE_CTX_FORMAT))
486 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
487 #pragma warning(disable:4204) /* nonstandard extension used: non-constant aggregate initializer */
488 #define memccpy _memccpy
491 #if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || defined(__MINGW64__)
492 #define vsnprintf(s, sz, fmt, va) fake_vsnprintf(s, sz, fmt, va)
493 static int fake_vsnprintf(char *s
, size_t sz
, const char *fmt
, va_list ap
)
495 const int n
= vsnprintf_s(s
, sz
, _TRUNCATE
, fmt
, ap
);
496 return 0 < n
? n
: (int)sz
+ 1; /* no need in _vscprintf() for now */
498 #if BT_LOG_OPTIMIZE_SIZE
499 #define snprintf(s, sz, ...) fake_snprintf(s, sz, __VA_ARGS__)
500 static int fake_snprintf(char *s
, size_t sz
, const char *fmt
, ...)
504 const int n
= fake_vsnprintf(s
, sz
, fmt
, va
);
511 typedef void (*time_cb
)(struct tm
*const tm
, unsigned *const usec
);
512 typedef void (*pid_cb
)(int *const pid
, int *const tid
);
513 typedef void (*buffer_cb
)(bt_log_message
*msg
, char *buf
);
515 typedef struct src_location
517 const char *const func
;
518 const char *const file
;
523 typedef struct mem_block
530 static void time_callback(struct tm
*const tm
, unsigned *const usec
);
531 static void pid_callback(int *const pid
, int *const tid
);
532 static void buffer_callback(bt_log_message
*msg
, char *buf
);
534 STATIC_ASSERT(eol_fits_eol_sz
, sizeof(BT_LOG_EOL
) <= BT_LOG_EOL_SZ
);
535 STATIC_ASSERT(eol_sz_greater_than_zero
, 0 < BT_LOG_EOL_SZ
);
536 STATIC_ASSERT(eol_sz_less_than_buf_sz
, BT_LOG_EOL_SZ
< BT_LOG_BUF_SZ
);
537 #if !defined(_WIN32) && !defined(_WIN64)
538 STATIC_ASSERT(buf_sz_less_than_pipe_buf
, BT_LOG_BUF_SZ
<= PIPE_BUF
);
540 static const char c_hex
[] = "0123456789abcdef";
542 static INSTRUMENTED_CONST
unsigned g_buf_sz
= BT_LOG_BUF_SZ
- BT_LOG_EOL_SZ
;
543 static INSTRUMENTED_CONST time_cb g_time_cb
= time_callback
;
544 static INSTRUMENTED_CONST pid_cb g_pid_cb
= pid_callback
;
545 static INSTRUMENTED_CONST buffer_cb g_buffer_cb
= buffer_callback
;
547 #if BT_LOG_USE_ANDROID_LOG
548 #include <android/log.h>
550 static INLINE
int android_lvl(const int lvl
)
555 return ANDROID_LOG_VERBOSE
;
557 return ANDROID_LOG_DEBUG
;
559 return ANDROID_LOG_INFO
;
561 return ANDROID_LOG_WARN
;
563 return ANDROID_LOG_ERROR
;
565 return ANDROID_LOG_FATAL
;
567 ASSERT_UNREACHABLE("Bad log level");
568 return ANDROID_LOG_UNKNOWN
;
572 static void out_android_callback(const bt_log_message
*const msg
, void *arg
)
576 const char *tag
= msg
->p
;
577 if (msg
->tag_e
!= msg
->tag_b
)
582 __android_log_print(android_lvl(msg
->lvl
), tag
, "%s", msg
->msg_b
);
585 enum { OUT_ANDROID_MASK
= BT_LOG_PUT_STD
& ~BT_LOG_PUT_CTX
};
586 #define OUT_ANDROID OUT_ANDROID_MASK, 0, out_android_callback
590 #include <CoreFoundation/CoreFoundation.h>
591 CF_EXPORT
void CFLog(int32_t level
, CFStringRef format
, ...);
593 static INLINE
int apple_lvl(const int lvl
)
598 return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;
600 return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;
602 return 6; /* ASL_LEVEL_INFO / kCFLogLevelInfo */;
604 return 4; /* ASL_LEVEL_WARNING / kCFLogLevelWarning */;
606 return 3; /* ASL_LEVEL_ERR / kCFLogLevelError */;
608 return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;
610 ASSERT_UNREACHABLE("Bad log level");
611 return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;
615 static void out_nslog_callback(const bt_log_message
*const msg
, void *arg
)
619 CFLog(apple_lvl(msg
->lvl
), CFSTR("%s"), msg
->tag_b
);
622 enum { OUT_NSLOG_MASK
= BT_LOG_PUT_STD
& ~BT_LOG_PUT_CTX
};
623 #define OUT_NSLOG OUT_NSLOG_MASK, 0, out_nslog_callback
626 #if BT_LOG_USE_DEBUGSTRING
629 static void out_debugstring_callback(const bt_log_message
*const msg
, void *arg
)
634 OutputDebugStringA(msg
->buf
);
637 enum { OUT_DEBUGSTRING_MASK
= BT_LOG_PUT_STD
};
638 #define OUT_DEBUGSTRING OUT_DEBUGSTRING_MASK, 0, out_debugstring_callback
642 void bt_log_out_stderr_callback(const bt_log_message
*const msg
, void *arg
)
645 const size_t eol_len
= sizeof(BT_LOG_EOL
) - 1;
646 memcpy(msg
->p
, BT_LOG_EOL
, eol_len
);
647 #if defined(_WIN32) || defined(_WIN64)
648 /* WriteFile() is atomic for local files opened with FILE_APPEND_DATA and
649 without FILE_WRITE_DATA */
650 WriteFile(GetStdHandle(STD_ERROR_HANDLE
), msg
->buf
,
651 (DWORD
)(msg
->p
- msg
->buf
+ eol_len
), 0, 0);
653 /* write() is atomic for buffers less than or equal to PIPE_BUF. */
654 RETVAL_UNUSED(write(STDERR_FILENO
, msg
->buf
,
655 (size_t)(msg
->p
- msg
->buf
) + eol_len
));
659 static const bt_log_output out_stderr
= {BT_LOG_OUT_STDERR
};
661 #if !BT_LOG_EXTERN_TAG_PREFIX
662 BT_LOG_DEFINE_TAG_PREFIX
= 0;
665 #if !BT_LOG_EXTERN_GLOBAL_FORMAT
666 BT_LOG_DEFINE_GLOBAL_FORMAT
= {BT_LOG_MEM_WIDTH
};
669 #if !BT_LOG_EXTERN_GLOBAL_OUTPUT
670 #if BT_LOG_USE_ANDROID_LOG
671 BT_LOG_DEFINE_GLOBAL_OUTPUT
= {OUT_ANDROID
};
672 #elif BT_LOG_USE_NSLOG
673 BT_LOG_DEFINE_GLOBAL_OUTPUT
= {OUT_NSLOG
};
674 #elif BT_LOG_USE_DEBUGSTRING
675 BT_LOG_DEFINE_GLOBAL_OUTPUT
= {OUT_DEBUGSTRING
};
677 BT_LOG_DEFINE_GLOBAL_OUTPUT
= {BT_LOG_OUT_STDERR
};
681 #if !BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
682 BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL
= 0;
685 const bt_log_spec _bt_log_stderr_spec
=
687 BT_LOG_GLOBAL_FORMAT
,
691 static const bt_log_spec global_spec
=
693 BT_LOG_GLOBAL_FORMAT
,
694 BT_LOG_GLOBAL_OUTPUT
,
697 #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(LEVEL, BT_LOG_MESSAGE_CTX_FORMAT)
698 static char lvl_char(const int lvl
)
715 ASSERT_UNREACHABLE("Bad log level");
721 #define GCCVER_LESS(MAJOR, MINOR, PATCH) \
722 (__GNUC__ < MAJOR || \
723 (__GNUC__ == MAJOR && (__GNUC_MINOR__ < MINOR || \
724 (__GNUC_MINOR__ == MINOR && __GNUC_PATCHLEVEL__ < PATCH))))
726 #if !defined(__clang__) && defined(__GNUC__) && GCCVER_LESS(4,7,0)
727 #define __atomic_load_n(vp, model) __sync_fetch_and_add(vp, 0)
728 #define __atomic_fetch_add(vp, n, model) __sync_fetch_and_add(vp, n)
729 #define __atomic_sub_fetch(vp, n, model) __sync_sub_and_fetch(vp, n)
730 #define __atomic_or_fetch(vp, n, model) __sync_or_and_fetch(vp, n)
731 #define __atomic_and_fetch(vp, n, model) __sync_and_and_fetch(vp, n)
732 /* Note: will not store old value of *vp in *ep (non-standard behaviour) */
733 #define __atomic_compare_exchange_n(vp, ep, d, weak, smodel, fmodel) \
734 __sync_bool_compare_and_swap(vp, *(ep), d)
737 #if !BT_LOG_OPTIMIZE_SIZE && !defined(_WIN32) && !defined(_WIN64)
739 #define TCACHE_STALE (0x40000000)
740 #define TCACHE_FLUID (0x40000000 | 0x80000000)
741 static unsigned g_tcache_mode
= TCACHE_STALE
;
742 static struct timeval g_tcache_tv
= {0, 0};
743 static struct tm g_tcache_tm
= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
745 static INLINE
int tcache_get(const struct timeval
*const tv
, struct tm
*const tm
)
748 mode
= __atomic_load_n(&g_tcache_mode
, __ATOMIC_RELAXED
);
749 if (0 == (mode
& TCACHE_FLUID
))
751 mode
= __atomic_fetch_add(&g_tcache_mode
, 1, __ATOMIC_ACQUIRE
);
752 if (0 == (mode
& TCACHE_FLUID
))
754 if (g_tcache_tv
.tv_sec
== tv
->tv_sec
)
757 __atomic_sub_fetch(&g_tcache_mode
, 1, __ATOMIC_RELEASE
);
760 __atomic_or_fetch(&g_tcache_mode
, TCACHE_STALE
, __ATOMIC_RELAXED
);
762 __atomic_sub_fetch(&g_tcache_mode
, 1, __ATOMIC_RELEASE
);
767 static INLINE
void tcache_set(const struct timeval
*const tv
, struct tm
*const tm
)
769 unsigned stale
= TCACHE_STALE
;
770 if (__atomic_compare_exchange_n(&g_tcache_mode
, &stale
, TCACHE_FLUID
,
771 0, __ATOMIC_ACQUIRE
, __ATOMIC_RELAXED
))
775 __atomic_and_fetch(&g_tcache_mode
, ~TCACHE_FLUID
, __ATOMIC_RELEASE
);
780 static void time_callback(struct tm
*const tm
, unsigned *const msec
)
782 #if !_BT_LOG_MESSAGE_FORMAT_DATETIME_USED
786 #if defined(_WIN32) || defined(_WIN64)
789 tm
->tm_year
= st
.wYear
;
790 tm
->tm_mon
= st
.wMonth
;
791 tm
->tm_mday
= st
.wDay
;
792 tm
->tm_wday
= st
.wDayOfWeek
;
793 tm
->tm_hour
= st
.wHour
;
794 tm
->tm_min
= st
.wMinute
;
795 tm
->tm_sec
= st
.wSecond
;
796 *msec
= st
.wMilliseconds
;
799 gettimeofday(&tv
, 0);
801 localtime_r(&tv
.tv_sec
, tm
);
803 if (!tcache_get(&tv
, tm
))
805 localtime_r(&tv
.tv_sec
, tm
);
809 *msec
= (unsigned)tv
.tv_usec
/ 1000;
814 static void pid_callback(int *const pid
, int *const tid
)
816 #if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(PID, BT_LOG_MESSAGE_CTX_FORMAT)
819 #if defined(_WIN32) || defined(_WIN64)
820 *pid
= GetCurrentProcessId();
826 #if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(TID, BT_LOG_MESSAGE_CTX_FORMAT)
829 #if defined(_WIN32) || defined(_WIN64)
830 *tid
= GetCurrentThreadId();
831 #elif defined(__CYGWIN__)
832 pthread_t thr
= pthread_self();
833 *tid
= (int)pthread_getsequence_np(&thr
);
834 #elif defined(__sun__)
835 *tid
= (int)pthread_self();
836 #elif defined(__ANDROID__)
838 #elif defined(__linux__)
839 *tid
= syscall(SYS_gettid
);
840 #elif defined(__MACH__)
841 *tid
= (int)pthread_mach_thread_np(pthread_self());
843 #define Platform not supported
848 static void buffer_callback(bt_log_message
*msg
, char *buf
)
850 msg
->e
= (msg
->p
= msg
->buf
= buf
) + g_buf_sz
;
853 #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, BT_LOG_MESSAGE_SRC_FORMAT)
854 static const char *funcname(const char *func
)
856 return func
? func
: "";
860 #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, BT_LOG_MESSAGE_SRC_FORMAT)
861 static const char *filename(const char *file
)
863 const char *f
= file
;
864 for (const char *p
= file
; 0 != *p
; ++p
)
866 if ('/' == *p
|| '\\' == *p
)
875 static INLINE
size_t nprintf_size(bt_log_message
*const msg
)
877 // *nprintf() always puts 0 in the end when input buffer is not empty. This
878 // 0 is not desired because its presence sets (ctx->p) to (ctx->e - 1) which
879 // leaves space for one more character. Some put_xxx() functions don't use
880 // *nprintf() and could use that last character. In that case log line will
881 // have multiple (two) half-written parts which is confusing. To workaround
882 // that we allow *nprintf() to write its 0 in the eol area (which is always
884 return (size_t)(msg
->e
- msg
->p
+ 1);
887 static INLINE
void put_nprintf(bt_log_message
*const msg
, const int n
)
891 msg
->p
= n
< msg
->e
- msg
->p
? msg
->p
+ n
: msg
->e
;
895 static INLINE
char *put_padding_r(const unsigned w
, const char wc
,
898 for (char *const b
= e
- w
; b
< p
; *--p
= wc
) {}
902 static char *put_integer_r(unsigned v
, const int sign
,
903 const unsigned w
, const char wc
, char *const e
)
905 static const char _signs
[] = {'-', '0', '+'};
906 static const char *const signs
= _signs
+ 1;
908 do { *--p
= '0' + v
% 10; } while (0 != (v
/= 10));
909 if (0 == sign
) return put_padding_r(w
, wc
, p
, e
);
913 return put_padding_r(w
, wc
, p
, e
);
915 p
= put_padding_r(w
, wc
, p
, e
+ 1);
920 static INLINE
char *put_uint_r(const unsigned v
, const unsigned w
, const char wc
,
923 return put_integer_r(v
, 0, w
, wc
, e
);
926 static INLINE
char *put_int_r(const int v
, const unsigned w
, const char wc
,
929 return 0 <= v
? put_integer_r((unsigned)v
, 0, w
, wc
, e
)
930 : put_integer_r((unsigned)-v
, -1, w
, wc
, e
);
933 static INLINE
char *put_stringn(const char *const s_p
, const char *const s_e
,
934 char *const p
, char *const e
)
936 const ptrdiff_t m
= e
- p
;
937 ptrdiff_t n
= s_e
- s_p
;
946 static INLINE
char *put_string(const char *s
, char *p
, char *const e
)
948 const ptrdiff_t n
= e
- p
;
949 char *const c
= (char *)memccpy(p
, s
, '\0', n
);
950 return 0 != c
? c
- 1: e
;
953 static INLINE
char *put_uint(unsigned v
, const unsigned w
, const char wc
,
954 char *const p
, char *const e
)
957 char *const se
= buf
+ _countof(buf
);
958 char *sp
= put_uint_r(v
, w
, wc
, se
);
959 return put_stringn(sp
, se
, p
, e
);
962 #define PUT_CSTR_R(p, STR) \
964 for (unsigned i = sizeof(STR) - 1; 0 < i--;) { \
969 #define PUT_CSTR_CHECKED(p, e, STR) \
971 for (unsigned i = 0; (e) > (p) && (sizeof(STR) - 1) > i; ++i) { \
976 /* F_INIT field support.
978 #define _BT_LOG_MESSAGE_FORMAT_INIT__
979 #define _BT_LOG_MESSAGE_FORMAT_INIT__YEAR
980 #define _BT_LOG_MESSAGE_FORMAT_INIT__MONTH
981 #define _BT_LOG_MESSAGE_FORMAT_INIT__DAY
982 #define _BT_LOG_MESSAGE_FORMAT_INIT__HOUR
983 #define _BT_LOG_MESSAGE_FORMAT_INIT__MINUTE
984 #define _BT_LOG_MESSAGE_FORMAT_INIT__SECOND
985 #define _BT_LOG_MESSAGE_FORMAT_INIT__MILLISECOND
986 #define _BT_LOG_MESSAGE_FORMAT_INIT__PID
987 #define _BT_LOG_MESSAGE_FORMAT_INIT__TID
988 #define _BT_LOG_MESSAGE_FORMAT_INIT__LEVEL
989 #define _BT_LOG_MESSAGE_FORMAT_INIT__TAG(ps, ts)
990 #define _BT_LOG_MESSAGE_FORMAT_INIT__FUNCTION
991 #define _BT_LOG_MESSAGE_FORMAT_INIT__FILENAME
992 #define _BT_LOG_MESSAGE_FORMAT_INIT__FILELINE
993 #define _BT_LOG_MESSAGE_FORMAT_INIT__S(s)
994 #define _BT_LOG_MESSAGE_FORMAT_INIT__F_INIT(expr) _PP_UNTUPLE(expr);
995 #define _BT_LOG_MESSAGE_FORMAT_INIT__F_UINT(w, v)
996 #define _BT_LOG_MESSAGE_FORMAT_INIT(field) \
997 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_INIT_, _, field)
999 /* Implements generation of printf-like format string for log message
1000 * format specification.
1002 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__ ""
1003 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__YEAR "%04u"
1004 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MONTH "%02u"
1005 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__DAY "%02u"
1006 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__HOUR "%02u"
1007 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MINUTE "%02u"
1008 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__SECOND "%02u"
1009 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MILLISECOND "%03u"
1010 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__PID "%5i"
1011 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TID "%5i"
1012 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__LEVEL "%c"
1013 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TAG UNDEFINED
1014 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FUNCTION "%s"
1015 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILENAME "%s"
1016 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILELINE "%u"
1017 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__S(s) s
1018 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_INIT(expr) ""
1019 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_UINT(w, v) "%" #w "u"
1020 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT(field) \
1021 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT_, _, field)
1023 /* Implements generation of printf-like format parameters for log message
1024 * format specification.
1026 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__
1027 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__YEAR ,(unsigned)(tm.tm_year + 1900)
1028 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH ,(unsigned)(tm.tm_mon + 1)
1029 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__DAY ,(unsigned)tm.tm_mday
1030 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__HOUR ,(unsigned)tm.tm_hour
1031 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MINUTE ,(unsigned)tm.tm_min
1032 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__SECOND ,(unsigned)tm.tm_sec
1033 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MILLISECOND ,(unsigned)msec
1034 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__PID ,pid
1035 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TID ,tid
1036 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__LEVEL ,(char)lvl_char(msg->lvl)
1037 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TAG UNDEFINED
1038 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FUNCTION ,funcname(src->func)
1039 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILENAME ,filename(src->file)
1040 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILELINE ,src->line
1041 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__S(s)
1042 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_INIT(expr)
1043 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_UINT(w, v) ,v
1044 #define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL(field) \
1045 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL_, _, field)
1047 /* Implements generation of put_xxx_t statements for log message specification.
1049 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__
1050 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__YEAR p = put_uint_r(tm.tm_year + 1900, 4, '0', p);
1051 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__MONTH p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p);
1052 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__DAY p = put_uint_r((unsigned)tm.tm_mday, 2, '0', p);
1053 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__HOUR p = put_uint_r((unsigned)tm.tm_hour, 2, '0', p);
1054 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__MINUTE p = put_uint_r((unsigned)tm.tm_min, 2, '0', p);
1055 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__SECOND p = put_uint_r((unsigned)tm.tm_sec, 2, '0', p);
1056 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__MILLISECOND p = put_uint_r(msec, 3, '0', p);
1057 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__PID p = put_int_r(pid, 5, ' ', p);
1058 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__TID p = put_int_r(tid, 5, ' ', p);
1059 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__LEVEL *--p = lvl_char(msg->lvl);
1060 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__TAG UNDEFINED
1061 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__FUNCTION UNDEFINED
1062 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__FILENAME UNDEFINED
1063 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__FILELINE UNDEFINED
1064 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__S(s) PUT_CSTR_R(p, s);
1065 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__F_INIT(expr)
1066 #define _BT_LOG_MESSAGE_FORMAT_PUT_R__F_UINT(w, v) p = put_uint_r(v, w, ' ', p);
1067 #define _BT_LOG_MESSAGE_FORMAT_PUT_R(field) \
1068 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PUT_R_, _, field)
1070 static void put_ctx(bt_log_message
*const msg
)
1072 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT
, BT_LOG_MESSAGE_CTX_FORMAT
)
1073 #if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_CTX_FORMAT)
1076 #if _BT_LOG_MESSAGE_FORMAT_DATETIME_USED
1079 g_time_cb(&tm
, &msec
);
1081 #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(PID, BT_LOG_MESSAGE_CTX_FORMAT) || \
1082 _BT_LOG_MESSAGE_FORMAT_CONTAINS(TID, BT_LOG_MESSAGE_CTX_FORMAT)
1084 g_pid_cb(&pid
, &tid
);
1087 #if BT_LOG_OPTIMIZE_SIZE
1089 n
= snprintf(msg
->p
, nprintf_size(msg
),
1090 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT
, BT_LOG_MESSAGE_CTX_FORMAT
)
1091 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL
, BT_LOG_MESSAGE_CTX_FORMAT
));
1092 put_nprintf(msg
, n
);
1095 char *const e
= buf
+ sizeof(buf
);
1097 _PP_RMAP(_BT_LOG_MESSAGE_FORMAT_PUT_R
, BT_LOG_MESSAGE_CTX_FORMAT
)
1098 msg
->p
= put_stringn(p
, e
, msg
->p
, msg
->e
);
1103 #define PUT_TAG(msg, tag, prefix_delim, tag_delim) \
1106 msg->tag_b = msg->p; \
1107 if (0 != (ch = _bt_log_tag_prefix)) { \
1108 for (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \
1110 if (0 != (ch = tag) && 0 != tag[0]) { \
1111 if (msg->tag_b != msg->p) { \
1112 PUT_CSTR_CHECKED(msg->p, msg->e, prefix_delim); \
1114 for (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \
1116 msg->tag_e = msg->p; \
1117 if (msg->tag_b != msg->p) { \
1118 PUT_CSTR_CHECKED(msg->p, msg->e, tag_delim); \
1122 /* Implements simple put statements for log message specification.
1124 #define _BT_LOG_MESSAGE_FORMAT_PUT__
1125 #define _BT_LOG_MESSAGE_FORMAT_PUT__YEAR UNDEFINED
1126 #define _BT_LOG_MESSAGE_FORMAT_PUT__MONTH UNDEFINED
1127 #define _BT_LOG_MESSAGE_FORMAT_PUT__DAY UNDEFINED
1128 #define _BT_LOG_MESSAGE_FORMAT_PUT__HOUR UNDEFINED
1129 #define _BT_LOG_MESSAGE_FORMAT_PUT__MINUTE UNDEFINED
1130 #define _BT_LOG_MESSAGE_FORMAT_PUT__SECOND UNDEFINED
1131 #define _BT_LOG_MESSAGE_FORMAT_PUT__MILLISECOND UNDEFINED
1132 #define _BT_LOG_MESSAGE_FORMAT_PUT__PID UNDEFINED
1133 #define _BT_LOG_MESSAGE_FORMAT_PUT__TID UNDEFINED
1134 #define _BT_LOG_MESSAGE_FORMAT_PUT__LEVEL UNDEFINED
1135 #define _BT_LOG_MESSAGE_FORMAT_PUT__TAG(pd, td) PUT_TAG(msg, tag, pd, td);
1136 #define _BT_LOG_MESSAGE_FORMAT_PUT__FUNCTION msg->p = put_string(funcname(src->func), msg->p, msg->e);
1137 #define _BT_LOG_MESSAGE_FORMAT_PUT__FILENAME msg->p = put_string(filename(src->file), msg->p, msg->e);
1138 #define _BT_LOG_MESSAGE_FORMAT_PUT__FILELINE msg->p = put_uint(src->line, 0, '\0', msg->p, msg->e);
1139 #define _BT_LOG_MESSAGE_FORMAT_PUT__S(s) PUT_CSTR_CHECKED(msg->p, msg->e, s);
1140 #define _BT_LOG_MESSAGE_FORMAT_PUT__F_INIT(expr)
1141 #define _BT_LOG_MESSAGE_FORMAT_PUT__F_UINT(w, v) msg->p = put_uint(v, w, ' ', msg->p, msg->e);
1142 #define _BT_LOG_MESSAGE_FORMAT_PUT(field) \
1143 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PUT_, _, field)
1145 static void put_tag(bt_log_message
*const msg
, const char *const tag
)
1147 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT
, BT_LOG_MESSAGE_TAG_FORMAT
)
1148 #if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(TAG, BT_LOG_MESSAGE_TAG_FORMAT)
1151 #if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_TAG_FORMAT)
1154 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PUT
, BT_LOG_MESSAGE_TAG_FORMAT
)
1158 static void put_src(bt_log_message
*const msg
, const src_location
*const src
)
1160 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT
, BT_LOG_MESSAGE_SRC_FORMAT
)
1161 #if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, BT_LOG_MESSAGE_SRC_FORMAT) && \
1162 !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, BT_LOG_MESSAGE_SRC_FORMAT) && \
1163 !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FILELINE, BT_LOG_MESSAGE_SRC_FORMAT)
1166 #if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_SRC_FORMAT)
1169 #if BT_LOG_OPTIMIZE_SIZE
1171 n
= snprintf(msg
->p
, nprintf_size(msg
),
1172 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT
, BT_LOG_MESSAGE_SRC_FORMAT
)
1173 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL
, BT_LOG_MESSAGE_SRC_FORMAT
));
1174 put_nprintf(msg
, n
);
1176 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PUT
, BT_LOG_MESSAGE_SRC_FORMAT
)
1181 static void put_msg(bt_log_message
*const msg
,
1182 const char *const fmt
, va_list va
)
1185 msg
->msg_b
= msg
->p
;
1186 n
= vsnprintf(msg
->p
, nprintf_size(msg
), fmt
, va
);
1187 put_nprintf(msg
, n
);
1190 static void output_mem(const bt_log_spec
*log
, bt_log_message
*const msg
,
1191 const mem_block
*const mem
)
1193 if (0 == mem
->d
|| 0 == mem
->d_sz
)
1197 const unsigned char *mem_p
= (const unsigned char *)mem
->d
;
1198 const unsigned char *const mem_e
= mem_p
+ mem
->d_sz
;
1199 const unsigned char *mem_cut
;
1200 const ptrdiff_t mem_width
= (ptrdiff_t)log
->format
->mem_width
;
1201 char *const hex_b
= msg
->msg_b
;
1202 char *const ascii_b
= hex_b
+ 2 * mem_width
+ 2;
1203 char *const ascii_e
= ascii_b
+ mem_width
;
1204 if (msg
->e
< ascii_e
)
1208 while (mem_p
!= mem_e
)
1211 char *ascii
= ascii_b
;
1212 for (mem_cut
= mem_width
< mem_e
- mem_p
? mem_p
+ mem_width
: mem_e
;
1213 mem_cut
!= mem_p
; ++mem_p
)
1215 const unsigned char ch
= *mem_p
;
1216 *hex
++ = c_hex
[(0xf0 & ch
) >> 4];
1217 *hex
++ = c_hex
[(0x0f & ch
)];
1218 *ascii
++ = isprint(ch
)? (char)ch
: '?';
1220 while (hex
!= ascii_b
)
1225 log
->output
->callback(msg
, log
->output
->arg
);
1230 void bt_log_set_tag_prefix(const char *const prefix
)
1232 _bt_log_tag_prefix
= prefix
;
1236 void bt_log_set_mem_width(const unsigned w
)
1238 _bt_log_global_format
.mem_width
= w
;
1242 void bt_log_set_output_level(const int lvl
)
1244 _bt_log_global_output_lvl
= lvl
;
1248 void bt_log_set_output_v(const unsigned mask
, void *const arg
,
1249 const bt_log_output_cb callback
)
1251 _bt_log_global_output
.mask
= mask
;
1252 _bt_log_global_output
.arg
= arg
;
1253 _bt_log_global_output
.callback
= callback
;
1256 static void _bt_log_write_imp(
1257 const bt_log_spec
*log
,
1258 const src_location
*const src
, const mem_block
*const mem
,
1259 const int lvl
, const char *const tag
, const char *const fmt
, va_list va
)
1262 char buf
[BT_LOG_BUF_SZ
];
1263 const unsigned mask
= log
->output
->mask
;
1266 g_buffer_cb(&msg
, buf
);
1267 const char *rst_color_p
= bt_common_color_reset();
1268 const char *rst_color_e
= rst_color_p
+ strlen(rst_color_p
);
1269 const char *color_p
= "";
1270 const char *color_e
= color_p
;
1274 color_p
= bt_common_color_fg_blue();
1275 color_e
= color_p
+ strlen(color_p
);
1278 color_p
= bt_common_color_fg_yellow();
1279 color_e
= color_p
+ strlen(color_p
);
1283 color_p
= bt_common_color_fg_red();
1284 color_e
= color_p
+ strlen(color_p
);
1290 msg
.p
= put_stringn(color_p
, color_e
, msg
.p
, msg
.e
);
1292 if (BT_LOG_PUT_CTX
& mask
)
1296 if (BT_LOG_PUT_TAG
& mask
)
1300 if (0 != src
&& BT_LOG_PUT_SRC
& mask
)
1304 if (BT_LOG_PUT_MSG
& mask
)
1306 put_msg(&msg
, fmt
, va
);
1308 msg
.p
= put_stringn(rst_color_p
, rst_color_e
, msg
.p
, msg
.e
);
1309 log
->output
->callback(&msg
, log
->output
->arg
);
1310 if (0 != mem
&& BT_LOG_PUT_MSG
& mask
)
1312 output_mem(log
, &msg
, mem
);
1317 void _bt_log_write_d(
1318 const char *const func
, const char *const file
, const unsigned line
,
1319 const int lvl
, const char *const tag
,
1320 const char *const fmt
, ...)
1322 const src_location src
= {func
, file
, line
};
1325 _bt_log_write_imp(&global_spec
, &src
, 0, lvl
, tag
, fmt
, va
);
1330 void _bt_log_write_aux_d(
1331 const char *const func
, const char *const file
, const unsigned line
,
1332 const bt_log_spec
*const log
, const int lvl
, const char *const tag
,
1333 const char *const fmt
, ...)
1335 const src_location src
= {func
, file
, line
};
1338 _bt_log_write_imp(log
, &src
, 0, lvl
, tag
, fmt
, va
);
1343 void _bt_log_write(const int lvl
, const char *const tag
,
1344 const char *const fmt
, ...)
1348 _bt_log_write_imp(&global_spec
, 0, 0, lvl
, tag
, fmt
, va
);
1353 void _bt_log_write_aux(
1354 const bt_log_spec
*const log
, const int lvl
, const char *const tag
,
1355 const char *const fmt
, ...)
1359 _bt_log_write_imp(log
, 0, 0, lvl
, tag
, fmt
, va
);
1364 void _bt_log_write_mem_d(
1365 const char *const func
, const char *const file
, const unsigned line
,
1366 const int lvl
, const char *const tag
,
1367 const void *const d
, const unsigned d_sz
,
1368 const char *const fmt
, ...)
1370 const src_location src
= {func
, file
, line
};
1371 const mem_block mem
= {d
, d_sz
};
1374 _bt_log_write_imp(&global_spec
, &src
, &mem
, lvl
, tag
, fmt
, va
);
1379 void _bt_log_write_mem_aux_d(
1380 const char *const func
, const char *const file
, const unsigned line
,
1381 const bt_log_spec
*const log
, const int lvl
, const char *const tag
,
1382 const void *const d
, const unsigned d_sz
,
1383 const char *const fmt
, ...)
1385 const src_location src
= {func
, file
, line
};
1386 const mem_block mem
= {d
, d_sz
};
1389 _bt_log_write_imp(log
, &src
, &mem
, lvl
, tag
, fmt
, va
);
1394 void _bt_log_write_mem(const int lvl
, const char *const tag
,
1395 const void *const d
, const unsigned d_sz
,
1396 const char *const fmt
, ...)
1398 const mem_block mem
= {d
, d_sz
};
1401 _bt_log_write_imp(&global_spec
, 0, &mem
, lvl
, tag
, fmt
, va
);
1406 void _bt_log_write_mem_aux(
1407 const bt_log_spec
*const log
, const int lvl
, const char *const tag
,
1408 const void *const d
, const unsigned d_sz
,
1409 const char *const fmt
, ...)
1411 const mem_block mem
= {d
, d_sz
};
1414 _bt_log_write_imp(log
, 0, &mem
, lvl
, tag
, fmt
, va
);