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