Port: Add Cygwin tid support to logging
[babeltrace.git] / logging / log.c
CommitLineData
beb0fb75
PP
1/*
2 * This is zf_log.c, modified with Babeltrace prefixes.
3 * See <https://github.com/wonder-mice/zf_log/>.
4 * See LICENSE.
5 */
6
7#include <babeltrace/babeltrace-internal.h>
557d8f39 8#include <babeltrace/common-internal.h>
beb0fb75 9
f61ad754
MJ
10#ifdef __CYGWIN__
11extern unsigned long pthread_getsequence_np(pthread_t *);
12#endif
13
beb0fb75
PP
14/* When defined, Android log (android/log.h) will be used by default instead of
15 * stderr (ignored on non-Android platforms). Date, time, pid and tid (context)
16 * will be provided by Android log. Android log features will be used to output
17 * log level and tag.
18 */
19#ifdef BT_LOG_USE_ANDROID_LOG
20 #undef BT_LOG_USE_ANDROID_LOG
21 #if defined(__ANDROID__)
22 #define BT_LOG_USE_ANDROID_LOG 1
23 #else
24 #define BT_LOG_USE_ANDROID_LOG 0
25 #endif
26#else
27 #define BT_LOG_USE_ANDROID_LOG 0
28#endif
29/* When defined, NSLog (uses Apple System Log) will be used instead of stderr
30 * (ignored on non-Apple platforms). Date, time, pid and tid (context) will be
31 * provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on
32 * non-public CFLog() function. Both use Apple System Log internally, but it's
33 * easier to call CFLog() from C than NSLog(). Current implementation doesn't
34 * support "%@" format specifier.
35 */
36#ifdef BT_LOG_USE_NSLOG
37 #undef BT_LOG_USE_NSLOG
38 #if defined(__APPLE__) && defined(__MACH__)
39 #define BT_LOG_USE_NSLOG 1
40 #else
41 #define BT_LOG_USE_NSLOG 0
42 #endif
43#else
44 #define BT_LOG_USE_NSLOG 0
45#endif
46/* When defined, OutputDebugString() will be used instead of stderr (ignored on
47 * non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with
48 * UTF-8 data.
49 */
50#ifdef BT_LOG_USE_DEBUGSTRING
51 #undef BT_LOG_USE_DEBUGSTRING
52 #if defined(_WIN32) || defined(_WIN64)
53 #define BT_LOG_USE_DEBUGSTRING 1
54 #else
55 #define BT_LOG_USE_DEBUGSTRING 0
56 #endif
57#else
58 #define BT_LOG_USE_DEBUGSTRING 0
59#endif
60/* When defined, bt_log library will not contain definition of tag prefix
61 * variable. In that case it must be defined elsewhere using
62 * BT_LOG_DEFINE_TAG_PREFIX macro, for example:
63 *
64 * BT_LOG_DEFINE_TAG_PREFIX = "ProcessName";
65 *
66 * This allows to specify custom value for static initialization and avoid
67 * overhead of setting this value in runtime.
68 */
69#ifdef BT_LOG_EXTERN_TAG_PREFIX
70 #undef BT_LOG_EXTERN_TAG_PREFIX
71 #define BT_LOG_EXTERN_TAG_PREFIX 1
72#else
73 #define BT_LOG_EXTERN_TAG_PREFIX 0
74#endif
75/* When defined, bt_log library will not contain definition of global format
76 * variable. In that case it must be defined elsewhere using
77 * BT_LOG_DEFINE_GLOBAL_FORMAT macro, for example:
78 *
79 * BT_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH};
80 *
81 * This allows to specify custom value for static initialization and avoid
82 * overhead of setting this value in runtime.
83 */
84#ifdef BT_LOG_EXTERN_GLOBAL_FORMAT
85 #undef BT_LOG_EXTERN_GLOBAL_FORMAT
86 #define BT_LOG_EXTERN_GLOBAL_FORMAT 1
87#else
88 #define BT_LOG_EXTERN_GLOBAL_FORMAT 0
89#endif
90/* When defined, bt_log library will not contain definition of global output
91 * variable. In that case it must be defined elsewhere using
92 * BT_LOG_DEFINE_GLOBAL_OUTPUT macro, for example:
93 *
94 * BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_PUT_STD, custom_output_callback};
95 *
96 * This allows to specify custom value for static initialization and avoid
97 * overhead of setting this value in runtime.
98 */
99#ifdef BT_LOG_EXTERN_GLOBAL_OUTPUT
100 #undef BT_LOG_EXTERN_GLOBAL_OUTPUT
101 #define BT_LOG_EXTERN_GLOBAL_OUTPUT 1
102#else
103 #define BT_LOG_EXTERN_GLOBAL_OUTPUT 0
104#endif
105/* When defined, bt_log library will not contain definition of global output
106 * level variable. In that case it must be defined elsewhere using
107 * BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example:
108 *
109 * BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = BT_LOG_WARN;
110 *
111 * This allows to specify custom value for static initialization and avoid
112 * overhead of setting this value in runtime.
113 */
114#ifdef BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
115 #undef BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
116 #define BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1
117#else
118 #define BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0
119#endif
120/* When defined, implementation will prefer smaller code size over speed.
121 * Very rough estimate is that code will be up to 2x smaller and up to 2x
122 * slower. Disabled by default.
123 */
124#ifdef BT_LOG_OPTIMIZE_SIZE
125 #undef BT_LOG_OPTIMIZE_SIZE
126 #define BT_LOG_OPTIMIZE_SIZE 1
127#else
128 #define BT_LOG_OPTIMIZE_SIZE 0
129#endif
130/* Size of the log line buffer. The buffer is allocated on stack. It limits
131 * maximum length of a log line.
132 */
133#ifndef BT_LOG_BUF_SZ
134 #define BT_LOG_BUF_SZ 512
135#endif
136/* Default number of bytes in one line of memory output. For large values
137 * BT_LOG_BUF_SZ also must be increased.
138 */
139#ifndef BT_LOG_MEM_WIDTH
140 #define BT_LOG_MEM_WIDTH 32
141#endif
142/* String to put in the end of each log line (can be empty). Its value used by
143 * stderr output callback. Its size used as a default value for BT_LOG_EOL_SZ.
144 */
145#ifndef BT_LOG_EOL
146 #define BT_LOG_EOL "\n"
147#endif
148/* Default delimiter that separates parts of log message. Can NOT contain '%'
149 * or '\0'.
150 *
151 * Log message format specifications can override (or ignore) this value. For
152 * more details see BT_LOG_MESSAGE_CTX_FORMAT, BT_LOG_MESSAGE_SRC_FORMAT and
153 * BT_LOG_MESSAGE_TAG_FORMAT.
154 */
155#ifndef BT_LOG_DEF_DELIMITER
156 #define BT_LOG_DEF_DELIMITER " "
157#endif
158/* Specifies log message context format. Log message context includes date,
159 * time, process id, thread id and message's log level. Custom information can
160 * be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,
161 * MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements),
162 * F_UINT(width, value).
163 *
164 * Must be defined as a tuple, for example:
165 *
166 * #define BT_LOG_MESSAGE_CTX_FORMAT (YEAR, S("."), MONTH, S("."), DAY, S(" > "))
167 *
168 * In that case, resulting log message will be:
169 *
170 * 2016.12.22 > TAG function@filename.c:line Message text
171 *
172 * Note, that tag, source location and message text are not impacted by
173 * this setting. See BT_LOG_MESSAGE_TAG_FORMAT and BT_LOG_MESSAGE_SRC_FORMAT.
174 *
175 * If message context must be visually separated from the rest of the message,
176 * it must be reflected in context format (notice trailing S(" > ") in the
177 * example above).
178 *
179 * S(str) adds constant string str. String can NOT contain '%' or '\0'.
180 *
181 * F_INIT(statements) adds initialization statement(s) that will be evaluated
182 * once for each log message. All statements are evaluated in specified order.
183 * Several F_INIT() fields can be used in every log message format
184 * specification. Fields, like F_UINT(width, value), are allowed to use results
185 * of initialization statements. If statement introduces variables (or other
186 * names, like structures) they must be prefixed with "f_". Statements must be
187 * enclosed into additional "()". Example:
188 *
189 * #define BT_LOG_MESSAGE_CTX_FORMAT \
190 * (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \
191 * YEAR, S("."), MONTH, S("."), DAY, S(" "), \
192 * F_UINT(5, f_ru.ru_nsignals), \
193 * S(" "))
194 *
195 * F_UINT(width, value) adds unsigned integer value extended with up to width
196 * spaces (for alignment purposes). Value can be any expression that evaluates
197 * to unsigned integer. If expression contains non-standard functions, they
198 * must be declared with F_INIT(). Example:
199 *
200 * #define BT_LOG_MESSAGE_CTX_FORMAT \
201 * (YEAR, S("."), MONTH, S("."), DAY, S(" "), \
202 * F_INIT(( unsigned tickcount(); )), \
203 * F_UINT(5, tickcount()), \
204 * S(" "))
205 *
206 * Other log message format specifications follow same rules, but have a
207 * different set of supported fields.
208 */
209#ifndef BT_LOG_MESSAGE_CTX_FORMAT
210 #define BT_LOG_MESSAGE_CTX_FORMAT \
211 (MONTH, S("-"), DAY, S(BT_LOG_DEF_DELIMITER), \
212 HOUR, S(":"), MINUTE, S(":"), SECOND, S("."), MILLISECOND, S(BT_LOG_DEF_DELIMITER), \
213 PID, S(BT_LOG_DEF_DELIMITER), TID, S(BT_LOG_DEF_DELIMITER), \
214 LEVEL, S(BT_LOG_DEF_DELIMITER))
215#endif
216/* Example:
217 */
218/* Specifies log message tag format. It includes tag prefix and tag. Custom
219 * information can be added as well. Supported fields:
220 * TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements),
221 * F_UINT(width, value).
222 *
223 * TAG(prefix_delimiter, tag_delimiter) adds following string to log message:
224 *
225 * PREFIX<prefix_delimiter>TAG<tag_delimiter>
226 *
227 * Prefix delimiter will be used only when prefix is not empty. Tag delimiter
228 * will be used only when prefixed tag is not empty. Example:
229 *
230 * #define BT_LOG_TAG_FORMAT (S("["), TAG(".", ""), S("] "))
231 *
232 * See BT_LOG_MESSAGE_CTX_FORMAT for details.
233 */
234#ifndef BT_LOG_MESSAGE_TAG_FORMAT
235 #define BT_LOG_MESSAGE_TAG_FORMAT \
236 (TAG(".", BT_LOG_DEF_DELIMITER))
237#endif
238/* Specifies log message source location format. It includes function name,
239 * file name and file line. Custom information can be added as well. Supported
240 * fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements),
241 * F_UINT(width, value).
242 *
243 * See BT_LOG_MESSAGE_CTX_FORMAT for details.
244 */
245#ifndef BT_LOG_MESSAGE_SRC_FORMAT
246 #define BT_LOG_MESSAGE_SRC_FORMAT \
247 (FUNCTION, S("@"), FILENAME, S(":"), FILELINE, S(BT_LOG_DEF_DELIMITER))
248#endif
249/* Fields that can be used in log message format specifications (see above).
250 * Mentioning them here explicitly, so we know that nobody else defined them
251 * before us. See BT_LOG_MESSAGE_CTX_FORMAT for details.
252 */
253#define YEAR YEAR
254#define MONTH MONTH
255#define DAY DAY
256#define MINUTE MINUTE
257#define SECOND SECOND
258#define MILLISECOND MILLISECOND
259#define PID PID
260#define TID TID
261#define LEVEL LEVEL
262#define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim)
263#define FUNCTION FUNCTION
264#define FILENAME FILENAME
265#define FILELINE FILELINE
266#define S(str) S(str)
267#define F_INIT(statements) F_INIT(statements)
268#define F_UINT(width, value) F_UINT(width, value)
269/* Number of bytes to reserve for EOL in the log line buffer (must be >0).
270 * Must be larger than or equal to length of BT_LOG_EOL with terminating null.
271 */
272#ifndef BT_LOG_EOL_SZ
273 #define BT_LOG_EOL_SZ sizeof(BT_LOG_EOL)
274#endif
275/* Compile instrumented version of the library to facilitate unit testing.
276 */
277#ifndef BT_LOG_INSTRUMENTED
278 #define BT_LOG_INSTRUMENTED 0
279#endif
280
281#if defined(__linux__)
282 #if !defined(__ANDROID__) && !defined(_GNU_SOURCE)
283 #define _GNU_SOURCE
284 #endif
285#endif
286#if defined(__MINGW32__)
287 #ifdef __STRICT_ANSI__
288 #undef __STRICT_ANSI__
289 #endif
290#endif
291#include <assert.h>
292#include <ctype.h>
293#include <string.h>
294#include <time.h>
295#include <stdarg.h>
296#include <stddef.h>
297#include <stdlib.h>
298#include <stdio.h>
00a52b39
PP
299
300#define BT_LOG_OUTPUT_LEVEL dummy
301
beb0fb75
PP
302#include <babeltrace/logging-internal.h>
303#include <babeltrace/logging.h>
304
305#if defined(_WIN32) || defined(_WIN64)
306 #include <windows.h>
307#else
308 #include <unistd.h>
309 #include <sys/time.h>
310 #if defined(__linux__)
311 #include <linux/limits.h>
312 #else
313 #include <sys/syslimits.h>
314 #endif
315#endif
316
317#if defined(__linux__)
318 #include <sys/prctl.h>
319 #include <sys/types.h>
320 #if !defined(__ANDROID__)
321 #include <sys/syscall.h>
322 #endif
323#endif
324#if defined(__MACH__)
325 #include <pthread.h>
326#endif
327
328#define INLINE _BT_LOG_INLINE
329#define VAR_UNUSED(var) (void)var
330#define RETVAL_UNUSED(expr) do { while(expr) break; } while(0)
331#define STATIC_ASSERT(name, cond) \
332 typedef char assert_##name[(cond)? 1: -1]
333#define ASSERT_UNREACHABLE(why) assert(!sizeof(why))
334#ifndef _countof
335 #define _countof(xs) (sizeof(xs) / sizeof((xs)[0]))
336#endif
337
338#if BT_LOG_INSTRUMENTED
339 #define INSTRUMENTED_CONST
340#else
341 #define INSTRUMENTED_CONST const
342#endif
343
344#define _PP_PASTE_2(a, b) a ## b
345#define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b)
346
347#define _PP_PASTE_3(a, b, c) a ## b ## c
348#define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c)
349
350/* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__
351 * as a single token and requires additional expansion to realize that it's
352 * actually a list. If not for it, there would be no need in this extra
353 * expansion.
354 */
355#define _PP_ID(x) x
356#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
357#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))
358
359/* There is a more efficient way to implement this, but it requires
360 * working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't
361 * have one.
362 */
363#define _PP_HEAD__(x, ...) x
364#define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~))
365#define _PP_HEAD(xs) _PP_HEAD_ xs
366#define _PP_TAIL_(x, ...) (__VA_ARGS__)
367#define _PP_TAIL(xs) _PP_TAIL_ xs
368#define _PP_UNTUPLE_(...) __VA_ARGS__
369#define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs
370
371/* Apply function macro to each element in tuple. Output is not
372 * enforced to be a tuple.
373 */
374#define _PP_MAP_1(f, xs) f(_PP_HEAD(xs))
375#define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs))
376#define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs))
377#define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs))
378#define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs))
379#define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs))
380#define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs))
381#define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs))
382#define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs))
383#define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs))
384#define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs))
385#define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs))
386#define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs))
387#define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs))
388#define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs))
389#define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs))
390#define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs))
391#define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs))
392#define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs))
393#define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs))
394#define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs))
395#define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs))
396#define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs))
397#define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs))
398#define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs) (f, xs)
399
400/* Apply function macro to each element in tuple in reverse order.
401 * Output is not enforced to be a tuple.
402 */
403#define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs))
404#define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
405#define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
406#define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
407#define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
408#define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
409#define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
410#define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
411#define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
412#define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
413#define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
414#define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
415#define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
416#define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
417#define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
418#define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
419#define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
420#define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
421#define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
422#define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
423#define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
424#define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
425#define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
426#define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
427#define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs) (f, xs)
428
429/* Used to implement _BT_LOG_MESSAGE_FORMAT_CONTAINS() macro. All possible
430 * fields must be mentioned here. Not counting F_INIT() here because it's
431 * somewhat special and is handled spearatly (at least for now).
432 */
433#define _BT_LOG_MESSAGE_FORMAT_MASK__ (0<<0)
434#define _BT_LOG_MESSAGE_FORMAT_MASK__YEAR (1<<1)
435#define _BT_LOG_MESSAGE_FORMAT_MASK__MONTH (1<<2)
436#define _BT_LOG_MESSAGE_FORMAT_MASK__DAY (1<<3)
437#define _BT_LOG_MESSAGE_FORMAT_MASK__HOUR (1<<4)
438#define _BT_LOG_MESSAGE_FORMAT_MASK__MINUTE (1<<5)
439#define _BT_LOG_MESSAGE_FORMAT_MASK__SECOND (1<<6)
440#define _BT_LOG_MESSAGE_FORMAT_MASK__MILLISECOND (1<<7)
441#define _BT_LOG_MESSAGE_FORMAT_MASK__PID (1<<8)
442#define _BT_LOG_MESSAGE_FORMAT_MASK__TID (1<<9)
443#define _BT_LOG_MESSAGE_FORMAT_MASK__LEVEL (1<<10)
444#define _BT_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts) (1<<11)
445#define _BT_LOG_MESSAGE_FORMAT_MASK__FUNCTION (1<<12)
446#define _BT_LOG_MESSAGE_FORMAT_MASK__FILENAME (1<<13)
447#define _BT_LOG_MESSAGE_FORMAT_MASK__FILELINE (1<<14)
448#define _BT_LOG_MESSAGE_FORMAT_MASK__S(s) (1<<15)
449#define _BT_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0<<16)
450#define _BT_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1<<17)
451#define _BT_LOG_MESSAGE_FORMAT_MASK(field) \
452 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_MASK_, _, field)
453
454/* Logical "or" of masks of fields used in specified format specification.
455 */
456#define _BT_LOG_MESSAGE_FORMAT_FIELDS(format) \
457 (0 _PP_MAP(| _BT_LOG_MESSAGE_FORMAT_MASK, format))
458
459/* Expands to expressions that evaluates to true if field is used in
460 * specified format specification. Example:
461 *
462 * #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT, BT_LOG_MESSAGE_CTX_FORMAT)
463 * ...
464 * #endif
465 */
466#define _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, format) \
467 (_BT_LOG_MESSAGE_FORMAT_MASK(field) & _BT_LOG_MESSAGE_FORMAT_FIELDS(format))
468
469/* Same, but checks all supported format specifications.
470 */
471#define _BT_LOG_MESSAGE_FORMAT_FIELD_USED(field) \
472 (_BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_CTX_FORMAT) || \
473 _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_TAG_FORMAT) || \
474 _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_SRC_FORMAT))
475
476#define _BT_LOG_MESSAGE_FORMAT_DATETIME_USED \
477 (_BT_LOG_MESSAGE_FORMAT_CONTAINS(YEAR, BT_LOG_MESSAGE_CTX_FORMAT) || \
478 _BT_LOG_MESSAGE_FORMAT_CONTAINS(MONTH, BT_LOG_MESSAGE_CTX_FORMAT) || \
479 _BT_LOG_MESSAGE_FORMAT_CONTAINS(DAY, BT_LOG_MESSAGE_CTX_FORMAT) || \
480 _BT_LOG_MESSAGE_FORMAT_CONTAINS(HOUR, BT_LOG_MESSAGE_CTX_FORMAT) || \
481 _BT_LOG_MESSAGE_FORMAT_CONTAINS(MINUTE, BT_LOG_MESSAGE_CTX_FORMAT) || \
482 _BT_LOG_MESSAGE_FORMAT_CONTAINS(SECOND, BT_LOG_MESSAGE_CTX_FORMAT) || \
483 _BT_LOG_MESSAGE_FORMAT_CONTAINS(MILLISECOND, BT_LOG_MESSAGE_CTX_FORMAT))
484
485#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
486 #pragma warning(disable:4204) /* nonstandard extension used: non-constant aggregate initializer */
487 #define memccpy _memccpy
488#endif
489
490#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || defined(__MINGW64__)
491 #define vsnprintf(s, sz, fmt, va) fake_vsnprintf(s, sz, fmt, va)
492 static int fake_vsnprintf(char *s, size_t sz, const char *fmt, va_list ap)
493 {
494 const int n = vsnprintf_s(s, sz, _TRUNCATE, fmt, ap);
495 return 0 < n? n: (int)sz + 1; /* no need in _vscprintf() for now */
496 }
497 #if BT_LOG_OPTIMIZE_SIZE
498 #define snprintf(s, sz, ...) fake_snprintf(s, sz, __VA_ARGS__)
499 static int fake_snprintf(char *s, size_t sz, const char *fmt, ...)
500 {
501 va_list va;
502 va_start(va, fmt);
503 const int n = fake_vsnprintf(s, sz, fmt, va);
504 va_end(va);
505 return n;
506 }
507 #endif
508#endif
509
510typedef void (*time_cb)(struct tm *const tm, unsigned *const usec);
511typedef void (*pid_cb)(int *const pid, int *const tid);
512typedef void (*buffer_cb)(bt_log_message *msg, char *buf);
513
514typedef struct src_location
515{
516 const char *const func;
517 const char *const file;
518 const unsigned line;
519}
520src_location;
521
522typedef struct mem_block
523{
524 const void *const d;
525 const unsigned d_sz;
526}
527mem_block;
528
529static void time_callback(struct tm *const tm, unsigned *const usec);
530static void pid_callback(int *const pid, int *const tid);
531static void buffer_callback(bt_log_message *msg, char *buf);
532
533STATIC_ASSERT(eol_fits_eol_sz, sizeof(BT_LOG_EOL) <= BT_LOG_EOL_SZ);
534STATIC_ASSERT(eol_sz_greater_than_zero, 0 < BT_LOG_EOL_SZ);
535STATIC_ASSERT(eol_sz_less_than_buf_sz, BT_LOG_EOL_SZ < BT_LOG_BUF_SZ);
536#if !defined(_WIN32) && !defined(_WIN64)
537 STATIC_ASSERT(buf_sz_less_than_pipe_buf, BT_LOG_BUF_SZ <= PIPE_BUF);
538#endif
539static const char c_hex[] = "0123456789abcdef";
540
541static INSTRUMENTED_CONST unsigned g_buf_sz = BT_LOG_BUF_SZ - BT_LOG_EOL_SZ;
542static INSTRUMENTED_CONST time_cb g_time_cb = time_callback;
543static INSTRUMENTED_CONST pid_cb g_pid_cb = pid_callback;
544static INSTRUMENTED_CONST buffer_cb g_buffer_cb = buffer_callback;
545
546#if BT_LOG_USE_ANDROID_LOG
547 #include <android/log.h>
548
549 static INLINE int android_lvl(const int lvl)
550 {
551 switch (lvl)
552 {
553 case BT_LOG_VERBOSE:
554 return ANDROID_LOG_VERBOSE;
555 case BT_LOG_DEBUG:
556 return ANDROID_LOG_DEBUG;
557 case BT_LOG_INFO:
558 return ANDROID_LOG_INFO;
559 case BT_LOG_WARN:
560 return ANDROID_LOG_WARN;
561 case BT_LOG_ERROR:
562 return ANDROID_LOG_ERROR;
563 case BT_LOG_FATAL:
564 return ANDROID_LOG_FATAL;
565 default:
566 ASSERT_UNREACHABLE("Bad log level");
567 return ANDROID_LOG_UNKNOWN;
568 }
569 }
570
571 static void out_android_callback(const bt_log_message *const msg, void *arg)
572 {
573 VAR_UNUSED(arg);
574 *msg->p = 0;
575 const char *tag = msg->p;
576 if (msg->tag_e != msg->tag_b)
577 {
578 tag = msg->tag_b;
579 *msg->tag_e = 0;
580 }
581 __android_log_print(android_lvl(msg->lvl), tag, "%s", msg->msg_b);
582 }
583
584 enum { OUT_ANDROID_MASK = BT_LOG_PUT_STD & ~BT_LOG_PUT_CTX };
585 #define OUT_ANDROID OUT_ANDROID_MASK, 0, out_android_callback
586#endif
587
588#if BT_LOG_USE_NSLOG
589 #include <CoreFoundation/CoreFoundation.h>
590 CF_EXPORT void CFLog(int32_t level, CFStringRef format, ...);
591
592 static INLINE int apple_lvl(const int lvl)
593 {
594 switch (lvl)
595 {
596 case BT_LOG_VERBOSE:
597 return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;
598 case BT_LOG_DEBUG:
599 return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;
600 case BT_LOG_INFO:
601 return 6; /* ASL_LEVEL_INFO / kCFLogLevelInfo */;
602 case BT_LOG_WARN:
603 return 4; /* ASL_LEVEL_WARNING / kCFLogLevelWarning */;
604 case BT_LOG_ERROR:
605 return 3; /* ASL_LEVEL_ERR / kCFLogLevelError */;
606 case BT_LOG_FATAL:
607 return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;
608 default:
609 ASSERT_UNREACHABLE("Bad log level");
610 return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;
611 }
612 }
613
614 static void out_nslog_callback(const bt_log_message *const msg, void *arg)
615 {
616 VAR_UNUSED(arg);
617 *msg->p = 0;
618 CFLog(apple_lvl(msg->lvl), CFSTR("%s"), msg->tag_b);
619 }
620
621 enum { OUT_NSLOG_MASK = BT_LOG_PUT_STD & ~BT_LOG_PUT_CTX };
622 #define OUT_NSLOG OUT_NSLOG_MASK, 0, out_nslog_callback
623#endif
624
625#if BT_LOG_USE_DEBUGSTRING
626 #include <windows.h>
627
628 static void out_debugstring_callback(const bt_log_message *const msg, void *arg)
629 {
630 VAR_UNUSED(arg);
631 msg->p[0] = '\n';
632 msg->p[1] = '\0';
633 OutputDebugStringA(msg->buf);
634 }
635
636 enum { OUT_DEBUGSTRING_MASK = BT_LOG_PUT_STD };
637 #define OUT_DEBUGSTRING OUT_DEBUGSTRING_MASK, 0, out_debugstring_callback
638#endif
639
640BT_HIDDEN
641void bt_log_out_stderr_callback(const bt_log_message *const msg, void *arg)
642{
643 VAR_UNUSED(arg);
644 const size_t eol_len = sizeof(BT_LOG_EOL) - 1;
645 memcpy(msg->p, BT_LOG_EOL, eol_len);
646#if defined(_WIN32) || defined(_WIN64)
647 /* WriteFile() is atomic for local files opened with FILE_APPEND_DATA and
648 without FILE_WRITE_DATA */
649 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg->buf,
650 (DWORD)(msg->p - msg->buf + eol_len), 0, 0);
651#else
652 /* write() is atomic for buffers less than or equal to PIPE_BUF. */
653 RETVAL_UNUSED(write(STDERR_FILENO, msg->buf,
654 (size_t)(msg->p - msg->buf) + eol_len));
655#endif
656}
657
658static const bt_log_output out_stderr = {BT_LOG_OUT_STDERR};
659
660#if !BT_LOG_EXTERN_TAG_PREFIX
661 BT_LOG_DEFINE_TAG_PREFIX = 0;
662#endif
663
664#if !BT_LOG_EXTERN_GLOBAL_FORMAT
665 BT_LOG_DEFINE_GLOBAL_FORMAT = {BT_LOG_MEM_WIDTH};
666#endif
667
668#if !BT_LOG_EXTERN_GLOBAL_OUTPUT
669 #if BT_LOG_USE_ANDROID_LOG
670 BT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_ANDROID};
671 #elif BT_LOG_USE_NSLOG
672 BT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_NSLOG};
673 #elif BT_LOG_USE_DEBUGSTRING
674 BT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_DEBUGSTRING};
675 #else
676 BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_OUT_STDERR};
677 #endif
678#endif
679
680#if !BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
681 BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0;
682#endif
683
684const bt_log_spec _bt_log_stderr_spec =
685{
686 BT_LOG_GLOBAL_FORMAT,
687 &out_stderr,
688};
689
690static const bt_log_spec global_spec =
691{
692 BT_LOG_GLOBAL_FORMAT,
693 BT_LOG_GLOBAL_OUTPUT,
694};
695
696#if _BT_LOG_MESSAGE_FORMAT_CONTAINS(LEVEL, BT_LOG_MESSAGE_CTX_FORMAT)
697static char lvl_char(const int lvl)
698{
699 switch (lvl)
700 {
701 case BT_LOG_VERBOSE:
702 return 'V';
703 case BT_LOG_DEBUG:
704 return 'D';
705 case BT_LOG_INFO:
706 return 'I';
707 case BT_LOG_WARN:
708 return 'W';
709 case BT_LOG_ERROR:
710 return 'E';
711 case BT_LOG_FATAL:
712 return 'F';
713 default:
714 ASSERT_UNREACHABLE("Bad log level");
715 return '?';
716 }
717}
718#endif
719
720#define GCCVER_LESS(MAJOR, MINOR, PATCH) \
721 (__GNUC__ < MAJOR || \
722 (__GNUC__ == MAJOR && (__GNUC_MINOR__ < MINOR || \
723 (__GNUC_MINOR__ == MINOR && __GNUC_PATCHLEVEL__ < PATCH))))
724
725#if !defined(__clang__) && defined(__GNUC__) && GCCVER_LESS(4,7,0)
726 #define __atomic_load_n(vp, model) __sync_fetch_and_add(vp, 0)
727 #define __atomic_fetch_add(vp, n, model) __sync_fetch_and_add(vp, n)
728 #define __atomic_sub_fetch(vp, n, model) __sync_sub_and_fetch(vp, n)
729 #define __atomic_or_fetch(vp, n, model) __sync_or_and_fetch(vp, n)
730 #define __atomic_and_fetch(vp, n, model) __sync_and_and_fetch(vp, n)
731 /* Note: will not store old value of *vp in *ep (non-standard behaviour) */
732 #define __atomic_compare_exchange_n(vp, ep, d, weak, smodel, fmodel) \
733 __sync_bool_compare_and_swap(vp, *(ep), d)
734#endif
735
736#if !BT_LOG_OPTIMIZE_SIZE && !defined(_WIN32) && !defined(_WIN64)
737#define TCACHE
738#define TCACHE_STALE (0x40000000)
739#define TCACHE_FLUID (0x40000000 | 0x80000000)
740static unsigned g_tcache_mode = TCACHE_STALE;
741static struct timeval g_tcache_tv = {0, 0};
742static struct tm g_tcache_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
743
744static INLINE int tcache_get(const struct timeval *const tv, struct tm *const tm)
745{
746 unsigned mode;
747 mode = __atomic_load_n(&g_tcache_mode, __ATOMIC_RELAXED);
748 if (0 == (mode & TCACHE_FLUID))
749 {
750 mode = __atomic_fetch_add(&g_tcache_mode, 1, __ATOMIC_ACQUIRE);
751 if (0 == (mode & TCACHE_FLUID))
752 {
753 if (g_tcache_tv.tv_sec == tv->tv_sec)
754 {
755 *tm = g_tcache_tm;
756 __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
757 return !0;
758 }
759 __atomic_or_fetch(&g_tcache_mode, TCACHE_STALE, __ATOMIC_RELAXED);
760 }
761 __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
762 }
763 return 0;
764}
765
766static INLINE void tcache_set(const struct timeval *const tv, struct tm *const tm)
767{
768 unsigned stale = TCACHE_STALE;
769 if (__atomic_compare_exchange_n(&g_tcache_mode, &stale, TCACHE_FLUID,
770 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
771 {
772 g_tcache_tv = *tv;
773 g_tcache_tm = *tm;
774 __atomic_and_fetch(&g_tcache_mode, ~TCACHE_FLUID, __ATOMIC_RELEASE);
775 }
776}
777#endif
778
779static void time_callback(struct tm *const tm, unsigned *const msec)
780{
781#if !_BT_LOG_MESSAGE_FORMAT_DATETIME_USED
782 VAR_UNUSED(tm);
783 VAR_UNUSED(msec);
784#else
785 #if defined(_WIN32) || defined(_WIN64)
786 SYSTEMTIME st;
787 GetLocalTime(&st);
788 tm->tm_year = st.wYear;
789 tm->tm_mon = st.wMonth;
790 tm->tm_mday = st.wDay;
791 tm->tm_wday = st.wDayOfWeek;
792 tm->tm_hour = st.wHour;
793 tm->tm_min = st.wMinute;
794 tm->tm_sec = st.wSecond;
795 *msec = st.wMilliseconds;
796 #else
797 struct timeval tv;
798 gettimeofday(&tv, 0);
799 #ifndef TCACHE
800 localtime_r(&tv.tv_sec, tm);
801 #else
802 if (!tcache_get(&tv, tm))
803 {
804 localtime_r(&tv.tv_sec, tm);
805 tcache_set(&tv, tm);
806 }
807 #endif
808 *msec = (unsigned)tv.tv_usec / 1000;
809 #endif
810#endif
811}
812
813static void pid_callback(int *const pid, int *const tid)
814{
815#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(PID, BT_LOG_MESSAGE_CTX_FORMAT)
816 VAR_UNUSED(pid);
817#else
818 #if defined(_WIN32) || defined(_WIN64)
819 *pid = GetCurrentProcessId();
820 #else
821 *pid = getpid();
822 #endif
823#endif
824
825#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(TID, BT_LOG_MESSAGE_CTX_FORMAT)
826 VAR_UNUSED(tid);
827#else
828 #if defined(_WIN32) || defined(_WIN64)
829 *tid = GetCurrentThreadId();
f61ad754
MJ
830 #elif defined(__CYGWIN__)
831 pthread_t thr = pthread_self();
832 *tid = (int)pthread_getsequence_np(&thr);
beb0fb75
PP
833 #elif defined(__ANDROID__)
834 *tid = gettid();
835 #elif defined(__linux__)
836 *tid = syscall(SYS_gettid);
837 #elif defined(__MACH__)
838 *tid = (int)pthread_mach_thread_np(pthread_self());
839 #else
840 #define Platform not supported
841 #endif
842#endif
843}
844
845static void buffer_callback(bt_log_message *msg, char *buf)
846{
847 msg->e = (msg->p = msg->buf = buf) + g_buf_sz;
848}
849
850#if _BT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, BT_LOG_MESSAGE_SRC_FORMAT)
851static const char *funcname(const char *func)
852{
853 return func? func: "";
854}
855#endif
856
857#if _BT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, BT_LOG_MESSAGE_SRC_FORMAT)
858static const char *filename(const char *file)
859{
860 const char *f = file;
861 for (const char *p = file; 0 != *p; ++p)
862 {
863 if ('/' == *p || '\\' == *p)
864 {
865 f = p + 1;
866 }
867 }
868 return f;
869}
870#endif
871
872static INLINE size_t nprintf_size(bt_log_message *const msg)
873{
874 // *nprintf() always puts 0 in the end when input buffer is not empty. This
875 // 0 is not desired because its presence sets (ctx->p) to (ctx->e - 1) which
876 // leaves space for one more character. Some put_xxx() functions don't use
877 // *nprintf() and could use that last character. In that case log line will
878 // have multiple (two) half-written parts which is confusing. To workaround
879 // that we allow *nprintf() to write its 0 in the eol area (which is always
880 // not empty).
881 return (size_t)(msg->e - msg->p + 1);
882}
883
884static INLINE void put_nprintf(bt_log_message *const msg, const int n)
885{
886 if (0 < n)
887 {
888 msg->p = n < msg->e - msg->p? msg->p + n: msg->e;
889 }
890}
891
892static INLINE char *put_padding_r(const unsigned w, const char wc,
893 char *p, char *e)
894{
895 for (char *const b = e - w; b < p; *--p = wc) {}
896 return p;
897}
898
899static char *put_integer_r(unsigned v, const int sign,
900 const unsigned w, const char wc, char *const e)
901{
902 static const char _signs[] = {'-', '0', '+'};
903 static const char *const signs = _signs + 1;
904 char *p = e;
905 do { *--p = '0' + v % 10; } while (0 != (v /= 10));
906 if (0 == sign) return put_padding_r(w, wc, p, e);
907 if ('0' != wc)
908 {
909 *--p = signs[sign];
910 return put_padding_r(w, wc, p, e);
911 }
912 p = put_padding_r(w, wc, p, e + 1);
913 *--p = signs[sign];
914 return p;
915}
916
917static INLINE char *put_uint_r(const unsigned v, const unsigned w, const char wc,
918 char *const e)
919{
920 return put_integer_r(v, 0, w, wc, e);
921}
922
923static INLINE char *put_int_r(const int v, const unsigned w, const char wc,
924 char *const e)
925{
926 return 0 <= v? put_integer_r((unsigned)v, 0, w, wc, e)
927 : put_integer_r((unsigned)-v, -1, w, wc, e);
928}
929
930static INLINE char *put_stringn(const char *const s_p, const char *const s_e,
931 char *const p, char *const e)
932{
933 const ptrdiff_t m = e - p;
934 ptrdiff_t n = s_e - s_p;
935 if (n > m)
936 {
937 n = m;
938 }
939 memcpy(p, s_p, n);
940 return p + n;
941}
942
943static INLINE char *put_string(const char *s, char *p, char *const e)
944{
945 const ptrdiff_t n = e - p;
946 char *const c = (char *)memccpy(p, s, '\0', n);
947 return 0 != c? c - 1: e;
948}
949
950static INLINE char *put_uint(unsigned v, const unsigned w, const char wc,
951 char *const p, char *const e)
952{
953 char buf[16];
954 char *const se = buf + _countof(buf);
955 char *sp = put_uint_r(v, w, wc, se);
956 return put_stringn(sp, se, p, e);
957}
958
959#define PUT_CSTR_R(p, STR) \
960 do { \
961 for (unsigned i = sizeof(STR) - 1; 0 < i--;) { \
962 *--(p) = (STR)[i]; \
963 } \
964 } _BT_LOG_ONCE
965
966#define PUT_CSTR_CHECKED(p, e, STR) \
967 do { \
968 for (unsigned i = 0; (e) > (p) && (sizeof(STR) - 1) > i; ++i) { \
969 *(p)++ = (STR)[i]; \
970 } \
971 } _BT_LOG_ONCE
972
973/* F_INIT field support.
974 */
975#define _BT_LOG_MESSAGE_FORMAT_INIT__
976#define _BT_LOG_MESSAGE_FORMAT_INIT__YEAR
977#define _BT_LOG_MESSAGE_FORMAT_INIT__MONTH
978#define _BT_LOG_MESSAGE_FORMAT_INIT__DAY
979#define _BT_LOG_MESSAGE_FORMAT_INIT__HOUR
980#define _BT_LOG_MESSAGE_FORMAT_INIT__MINUTE
981#define _BT_LOG_MESSAGE_FORMAT_INIT__SECOND
982#define _BT_LOG_MESSAGE_FORMAT_INIT__MILLISECOND
983#define _BT_LOG_MESSAGE_FORMAT_INIT__PID
984#define _BT_LOG_MESSAGE_FORMAT_INIT__TID
985#define _BT_LOG_MESSAGE_FORMAT_INIT__LEVEL
986#define _BT_LOG_MESSAGE_FORMAT_INIT__TAG(ps, ts)
987#define _BT_LOG_MESSAGE_FORMAT_INIT__FUNCTION
988#define _BT_LOG_MESSAGE_FORMAT_INIT__FILENAME
989#define _BT_LOG_MESSAGE_FORMAT_INIT__FILELINE
990#define _BT_LOG_MESSAGE_FORMAT_INIT__S(s)
991#define _BT_LOG_MESSAGE_FORMAT_INIT__F_INIT(expr) _PP_UNTUPLE(expr);
992#define _BT_LOG_MESSAGE_FORMAT_INIT__F_UINT(w, v)
993#define _BT_LOG_MESSAGE_FORMAT_INIT(field) \
994 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_INIT_, _, field)
995
996/* Implements generation of printf-like format string for log message
997 * format specification.
998 */
999#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__ ""
1000#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__YEAR "%04u"
1001#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MONTH "%02u"
1002#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__DAY "%02u"
1003#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__HOUR "%02u"
1004#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MINUTE "%02u"
1005#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__SECOND "%02u"
1006#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MILLISECOND "%03u"
1007#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__PID "%5i"
1008#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TID "%5i"
1009#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__LEVEL "%c"
1010#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TAG UNDEFINED
1011#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FUNCTION "%s"
1012#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILENAME "%s"
1013#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILELINE "%u"
1014#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__S(s) s
1015#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_INIT(expr) ""
1016#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_UINT(w, v) "%" #w "u"
1017#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT(field) \
1018 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT_, _, field)
1019
1020/* Implements generation of printf-like format parameters for log message
1021 * format specification.
1022 */
1023#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__
1024#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__YEAR ,(unsigned)(tm.tm_year + 1900)
1025#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH ,(unsigned)(tm.tm_mon + 1)
1026#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__DAY ,(unsigned)tm.tm_mday
1027#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__HOUR ,(unsigned)tm.tm_hour
1028#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MINUTE ,(unsigned)tm.tm_min
1029#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__SECOND ,(unsigned)tm.tm_sec
1030#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MILLISECOND ,(unsigned)msec
1031#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__PID ,pid
1032#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TID ,tid
1033#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__LEVEL ,(char)lvl_char(msg->lvl)
1034#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TAG UNDEFINED
1035#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FUNCTION ,funcname(src->func)
1036#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILENAME ,filename(src->file)
1037#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILELINE ,src->line
1038#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__S(s)
1039#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_INIT(expr)
1040#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_UINT(w, v) ,v
1041#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL(field) \
1042 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL_, _, field)
1043
1044/* Implements generation of put_xxx_t statements for log message specification.
1045 */
1046#define _BT_LOG_MESSAGE_FORMAT_PUT_R__
1047#define _BT_LOG_MESSAGE_FORMAT_PUT_R__YEAR p = put_uint_r(tm.tm_year + 1900, 4, '0', p);
1048#define _BT_LOG_MESSAGE_FORMAT_PUT_R__MONTH p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p);
1049#define _BT_LOG_MESSAGE_FORMAT_PUT_R__DAY p = put_uint_r((unsigned)tm.tm_mday, 2, '0', p);
1050#define _BT_LOG_MESSAGE_FORMAT_PUT_R__HOUR p = put_uint_r((unsigned)tm.tm_hour, 2, '0', p);
1051#define _BT_LOG_MESSAGE_FORMAT_PUT_R__MINUTE p = put_uint_r((unsigned)tm.tm_min, 2, '0', p);
1052#define _BT_LOG_MESSAGE_FORMAT_PUT_R__SECOND p = put_uint_r((unsigned)tm.tm_sec, 2, '0', p);
1053#define _BT_LOG_MESSAGE_FORMAT_PUT_R__MILLISECOND p = put_uint_r(msec, 3, '0', p);
1054#define _BT_LOG_MESSAGE_FORMAT_PUT_R__PID p = put_int_r(pid, 5, ' ', p);
1055#define _BT_LOG_MESSAGE_FORMAT_PUT_R__TID p = put_int_r(tid, 5, ' ', p);
1056#define _BT_LOG_MESSAGE_FORMAT_PUT_R__LEVEL *--p = lvl_char(msg->lvl);
1057#define _BT_LOG_MESSAGE_FORMAT_PUT_R__TAG UNDEFINED
1058#define _BT_LOG_MESSAGE_FORMAT_PUT_R__FUNCTION UNDEFINED
1059#define _BT_LOG_MESSAGE_FORMAT_PUT_R__FILENAME UNDEFINED
1060#define _BT_LOG_MESSAGE_FORMAT_PUT_R__FILELINE UNDEFINED
1061#define _BT_LOG_MESSAGE_FORMAT_PUT_R__S(s) PUT_CSTR_R(p, s);
1062#define _BT_LOG_MESSAGE_FORMAT_PUT_R__F_INIT(expr)
1063#define _BT_LOG_MESSAGE_FORMAT_PUT_R__F_UINT(w, v) p = put_uint_r(v, w, ' ', p);
1064#define _BT_LOG_MESSAGE_FORMAT_PUT_R(field) \
1065 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PUT_R_, _, field)
1066
1067static void put_ctx(bt_log_message *const msg)
1068{
1069 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT, BT_LOG_MESSAGE_CTX_FORMAT)
1070#if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_CTX_FORMAT)
1071 VAR_UNUSED(msg);
1072#else
1073 #if _BT_LOG_MESSAGE_FORMAT_DATETIME_USED
1074 struct tm tm;
1075 unsigned msec;
1076 g_time_cb(&tm, &msec);
1077 #endif
1078 #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(PID, BT_LOG_MESSAGE_CTX_FORMAT) || \
1079 _BT_LOG_MESSAGE_FORMAT_CONTAINS(TID, BT_LOG_MESSAGE_CTX_FORMAT)
1080 int pid, tid;
1081 g_pid_cb(&pid, &tid);
1082 #endif
1083
1084 #if BT_LOG_OPTIMIZE_SIZE
1085 int n;
1086 n = snprintf(msg->p, nprintf_size(msg),
1087 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT, BT_LOG_MESSAGE_CTX_FORMAT)
1088 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL, BT_LOG_MESSAGE_CTX_FORMAT));
1089 put_nprintf(msg, n);
1090 #else
1091 char buf[64];
1092 char *const e = buf + sizeof(buf);
1093 char *p = e;
1094 _PP_RMAP(_BT_LOG_MESSAGE_FORMAT_PUT_R, BT_LOG_MESSAGE_CTX_FORMAT)
1095 msg->p = put_stringn(p, e, msg->p, msg->e);
1096 #endif
1097#endif
1098}
1099
1100#define PUT_TAG(msg, tag, prefix_delim, tag_delim) \
1101 do { \
1102 const char *ch; \
1103 msg->tag_b = msg->p; \
1104 if (0 != (ch = _bt_log_tag_prefix)) { \
1105 for (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \
1106 } \
1107 if (0 != (ch = tag) && 0 != tag[0]) { \
1108 if (msg->tag_b != msg->p) { \
1109 PUT_CSTR_CHECKED(msg->p, msg->e, prefix_delim); \
1110 } \
1111 for (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \
1112 } \
1113 msg->tag_e = msg->p; \
1114 if (msg->tag_b != msg->p) { \
1115 PUT_CSTR_CHECKED(msg->p, msg->e, tag_delim); \
1116 } \
1117 } _BT_LOG_ONCE
1118
1119/* Implements simple put statements for log message specification.
1120 */
1121#define _BT_LOG_MESSAGE_FORMAT_PUT__
1122#define _BT_LOG_MESSAGE_FORMAT_PUT__YEAR UNDEFINED
1123#define _BT_LOG_MESSAGE_FORMAT_PUT__MONTH UNDEFINED
1124#define _BT_LOG_MESSAGE_FORMAT_PUT__DAY UNDEFINED
1125#define _BT_LOG_MESSAGE_FORMAT_PUT__HOUR UNDEFINED
1126#define _BT_LOG_MESSAGE_FORMAT_PUT__MINUTE UNDEFINED
1127#define _BT_LOG_MESSAGE_FORMAT_PUT__SECOND UNDEFINED
1128#define _BT_LOG_MESSAGE_FORMAT_PUT__MILLISECOND UNDEFINED
1129#define _BT_LOG_MESSAGE_FORMAT_PUT__PID UNDEFINED
1130#define _BT_LOG_MESSAGE_FORMAT_PUT__TID UNDEFINED
1131#define _BT_LOG_MESSAGE_FORMAT_PUT__LEVEL UNDEFINED
1132#define _BT_LOG_MESSAGE_FORMAT_PUT__TAG(pd, td) PUT_TAG(msg, tag, pd, td);
1133#define _BT_LOG_MESSAGE_FORMAT_PUT__FUNCTION msg->p = put_string(funcname(src->func), msg->p, msg->e);
1134#define _BT_LOG_MESSAGE_FORMAT_PUT__FILENAME msg->p = put_string(filename(src->file), msg->p, msg->e);
1135#define _BT_LOG_MESSAGE_FORMAT_PUT__FILELINE msg->p = put_uint(src->line, 0, '\0', msg->p, msg->e);
1136#define _BT_LOG_MESSAGE_FORMAT_PUT__S(s) PUT_CSTR_CHECKED(msg->p, msg->e, s);
1137#define _BT_LOG_MESSAGE_FORMAT_PUT__F_INIT(expr)
1138#define _BT_LOG_MESSAGE_FORMAT_PUT__F_UINT(w, v) msg->p = put_uint(v, w, ' ', msg->p, msg->e);
1139#define _BT_LOG_MESSAGE_FORMAT_PUT(field) \
1140 _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PUT_, _, field)
1141
1142static void put_tag(bt_log_message *const msg, const char *const tag)
1143{
1144 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT, BT_LOG_MESSAGE_TAG_FORMAT)
1145#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(TAG, BT_LOG_MESSAGE_TAG_FORMAT)
1146 VAR_UNUSED(tag);
1147#endif
1148#if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_TAG_FORMAT)
1149 VAR_UNUSED(msg);
1150#else
1151 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PUT, BT_LOG_MESSAGE_TAG_FORMAT)
1152#endif
1153}
1154
1155static void put_src(bt_log_message *const msg, const src_location *const src)
1156{
1157 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT, BT_LOG_MESSAGE_SRC_FORMAT)
1158#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, BT_LOG_MESSAGE_SRC_FORMAT) && \
1159 !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, BT_LOG_MESSAGE_SRC_FORMAT) && \
1160 !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FILELINE, BT_LOG_MESSAGE_SRC_FORMAT)
1161 VAR_UNUSED(src);
1162#endif
1163#if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_SRC_FORMAT)
1164 VAR_UNUSED(msg);
1165#else
1166 #if BT_LOG_OPTIMIZE_SIZE
1167 int n;
1168 n = snprintf(msg->p, nprintf_size(msg),
1169 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT, BT_LOG_MESSAGE_SRC_FORMAT)
1170 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL, BT_LOG_MESSAGE_SRC_FORMAT));
1171 put_nprintf(msg, n);
1172 #else
1173 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PUT, BT_LOG_MESSAGE_SRC_FORMAT)
1174 #endif
1175#endif
1176}
1177
1178static void put_msg(bt_log_message *const msg,
1179 const char *const fmt, va_list va)
1180{
1181 int n;
1182 msg->msg_b = msg->p;
1183 n = vsnprintf(msg->p, nprintf_size(msg), fmt, va);
1184 put_nprintf(msg, n);
1185}
1186
1187static void output_mem(const bt_log_spec *log, bt_log_message *const msg,
1188 const mem_block *const mem)
1189{
1190 if (0 == mem->d || 0 == mem->d_sz)
1191 {
1192 return;
1193 }
1194 const unsigned char *mem_p = (const unsigned char *)mem->d;
1195 const unsigned char *const mem_e = mem_p + mem->d_sz;
1196 const unsigned char *mem_cut;
1197 const ptrdiff_t mem_width = (ptrdiff_t)log->format->mem_width;
1198 char *const hex_b = msg->msg_b;
1199 char *const ascii_b = hex_b + 2 * mem_width + 2;
1200 char *const ascii_e = ascii_b + mem_width;
1201 if (msg->e < ascii_e)
1202 {
1203 return;
1204 }
1205 while (mem_p != mem_e)
1206 {
1207 char *hex = hex_b;
1208 char *ascii = ascii_b;
1209 for (mem_cut = mem_width < mem_e - mem_p? mem_p + mem_width: mem_e;
1210 mem_cut != mem_p; ++mem_p)
1211 {
1212 const unsigned char ch = *mem_p;
1213 *hex++ = c_hex[(0xf0 & ch) >> 4];
1214 *hex++ = c_hex[(0x0f & ch)];
1215 *ascii++ = isprint(ch)? (char)ch: '?';
1216 }
1217 while (hex != ascii_b)
1218 {
1219 *hex++ = ' ';
1220 }
1221 msg->p = ascii;
1222 log->output->callback(msg, log->output->arg);
1223 }
1224}
1225
1226BT_HIDDEN
1227void bt_log_set_tag_prefix(const char *const prefix)
1228{
1229 _bt_log_tag_prefix = prefix;
1230}
1231
1232BT_HIDDEN
1233void bt_log_set_mem_width(const unsigned w)
1234{
1235 _bt_log_global_format.mem_width = w;
1236}
1237
1238BT_HIDDEN
1239void bt_log_set_output_level(const int lvl)
1240{
1241 _bt_log_global_output_lvl = lvl;
1242}
1243
1244BT_HIDDEN
1245void bt_log_set_output_v(const unsigned mask, void *const arg,
1246 const bt_log_output_cb callback)
1247{
1248 _bt_log_global_output.mask = mask;
1249 _bt_log_global_output.arg = arg;
1250 _bt_log_global_output.callback = callback;
1251}
1252
1253static void _bt_log_write_imp(
1254 const bt_log_spec *log,
1255 const src_location *const src, const mem_block *const mem,
1256 const int lvl, const char *const tag, const char *const fmt, va_list va)
1257{
1258 bt_log_message msg;
1259 char buf[BT_LOG_BUF_SZ];
1260 const unsigned mask = log->output->mask;
1261 msg.lvl = lvl;
1262 msg.tag = tag;
1263 g_buffer_cb(&msg, buf);
557d8f39
PP
1264 const char *rst_color_p = bt_common_color_reset();
1265 const char *rst_color_e = rst_color_p + strlen(rst_color_p);
1266 const char *color_p = "";
1267 const char *color_e = color_p;
1268
1269 switch (lvl) {
1270 case BT_LOG_INFO:
1271 color_p = bt_common_color_fg_blue();
1272 color_e = color_p + strlen(color_p);
1273 break;
1274 case BT_LOG_WARN:
1275 color_p = bt_common_color_fg_yellow();
1276 color_e = color_p + strlen(color_p);
1277 break;
1278 case BT_LOG_ERROR:
1279 case BT_LOG_FATAL:
1280 color_p = bt_common_color_fg_red();
1281 color_e = color_p + strlen(color_p);
1282 break;
1283 default:
1284 break;
1285 }
1286
1287 msg.p = put_stringn(color_p, color_e, msg.p, msg.e);
1288
beb0fb75
PP
1289 if (BT_LOG_PUT_CTX & mask)
1290 {
1291 put_ctx(&msg);
1292 }
1293 if (BT_LOG_PUT_TAG & mask)
1294 {
1295 put_tag(&msg, tag);
1296 }
1297 if (0 != src && BT_LOG_PUT_SRC & mask)
1298 {
1299 put_src(&msg, src);
1300 }
1301 if (BT_LOG_PUT_MSG & mask)
1302 {
1303 put_msg(&msg, fmt, va);
1304 }
557d8f39 1305 msg.p = put_stringn(rst_color_p, rst_color_e, msg.p, msg.e);
beb0fb75
PP
1306 log->output->callback(&msg, log->output->arg);
1307 if (0 != mem && BT_LOG_PUT_MSG & mask)
1308 {
1309 output_mem(log, &msg, mem);
1310 }
1311}
1312
1313BT_HIDDEN
1314void _bt_log_write_d(
1315 const char *const func, const char *const file, const unsigned line,
1316 const int lvl, const char *const tag,
1317 const char *const fmt, ...)
1318{
1319 const src_location src = {func, file, line};
1320 va_list va;
1321 va_start(va, fmt);
1322 _bt_log_write_imp(&global_spec, &src, 0, lvl, tag, fmt, va);
1323 va_end(va);
1324}
1325
1326BT_HIDDEN
1327void _bt_log_write_aux_d(
1328 const char *const func, const char *const file, const unsigned line,
1329 const bt_log_spec *const log, const int lvl, const char *const tag,
1330 const char *const fmt, ...)
1331{
1332 const src_location src = {func, file, line};
1333 va_list va;
1334 va_start(va, fmt);
1335 _bt_log_write_imp(log, &src, 0, lvl, tag, fmt, va);
1336 va_end(va);
1337}
1338
1339BT_HIDDEN
1340void _bt_log_write(const int lvl, const char *const tag,
1341 const char *const fmt, ...)
1342{
1343 va_list va;
1344 va_start(va, fmt);
1345 _bt_log_write_imp(&global_spec, 0, 0, lvl, tag, fmt, va);
1346 va_end(va);
1347}
1348
1349BT_HIDDEN
1350void _bt_log_write_aux(
1351 const bt_log_spec *const log, const int lvl, const char *const tag,
1352 const char *const fmt, ...)
1353{
1354 va_list va;
1355 va_start(va, fmt);
1356 _bt_log_write_imp(log, 0, 0, lvl, tag, fmt, va);
1357 va_end(va);
1358}
1359
1360BT_HIDDEN
1361void _bt_log_write_mem_d(
1362 const char *const func, const char *const file, const unsigned line,
1363 const int lvl, const char *const tag,
1364 const void *const d, const unsigned d_sz,
1365 const char *const fmt, ...)
1366{
1367 const src_location src = {func, file, line};
1368 const mem_block mem = {d, d_sz};
1369 va_list va;
1370 va_start(va, fmt);
1371 _bt_log_write_imp(&global_spec, &src, &mem, lvl, tag, fmt, va);
1372 va_end(va);
1373}
1374
1375BT_HIDDEN
1376void _bt_log_write_mem_aux_d(
1377 const char *const func, const char *const file, const unsigned line,
1378 const bt_log_spec *const log, const int lvl, const char *const tag,
1379 const void *const d, const unsigned d_sz,
1380 const char *const fmt, ...)
1381{
1382 const src_location src = {func, file, line};
1383 const mem_block mem = {d, d_sz};
1384 va_list va;
1385 va_start(va, fmt);
1386 _bt_log_write_imp(log, &src, &mem, lvl, tag, fmt, va);
1387 va_end(va);
1388}
1389
1390BT_HIDDEN
1391void _bt_log_write_mem(const int lvl, const char *const tag,
1392 const void *const d, const unsigned d_sz,
1393 const char *const fmt, ...)
1394{
1395 const mem_block mem = {d, d_sz};
1396 va_list va;
1397 va_start(va, fmt);
1398 _bt_log_write_imp(&global_spec, 0, &mem, lvl, tag, fmt, va);
1399 va_end(va);
1400}
1401
1402BT_HIDDEN
1403void _bt_log_write_mem_aux(
1404 const bt_log_spec *const log, const int lvl, const char *const tag,
1405 const void *const d, const unsigned d_sz,
1406 const char *const fmt, ...)
1407{
1408 const mem_block mem = {d, d_sz};
1409 va_list va;
1410 va_start(va, fmt);
1411 _bt_log_write_imp(log, 0, &mem, lvl, tag, fmt, va);
1412 va_end(va);
1413}
This page took 0.077674 seconds and 4 git commands to generate.