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