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