MULE
0.0.1
Multi-Use Library Essentials
Toggle main menu visibility
Loading...
Searching...
No Matches
log.h
1
#pragma once
2
/**
3
* @defgroup mod_log Log
4
* @brief Levelled messages for people reading a terminal or a log file.
5
*
6
* - Each call writes one line, `LEVEL file:line: message`, with the level
7
* coloured when the output supports it.
8
* - Calls below the runtime level, set with log_set_level(), return before
9
* evaluating their arguments. Calls below #LOG_LEVEL_MIN compile to
10
* nothing.
11
* - Each line goes out in one `fwrite`, so lines from different threads do
12
* not interleave. Set the level and output before starting threads.
13
* - log_fatal() and log_assert() write, flush and abort, whatever the level.
14
*
15
* @snippet{trimleft} test_log.c log
16
*
17
* ## Colour
18
*
19
* log_color_enabled() follows the conventions other command-line tools use:
20
* - `NO_COLOR` set to anything non-empty turns colour off. It wins over
21
* everything else (https://no-color.org).
22
* - `CLICOLOR_FORCE` or `FORCE_COLOR` set to anything but empty or `0` turns
23
* colour on, even when the output is a pipe or a file.
24
* - Otherwise colour is on when the stream is a terminal and `TERM` is set
25
* and is not `dumb`.
26
*
27
* @snippet{trimleft} test_log.c color
28
* @{
29
*/
30
31
#include "base/base.h"
32
33
#include <stdio.h>
34
35
/** @name Levels and output
36
* What gets written, and where.
37
* @{ */
38
39
/** How much a message matters, from chattiest to most severe. */
40
typedef
enum
LogLevel
{
41
LOG_TRACE
,
/**< Step-by-step detail, usually off. */
42
LOG_DEBUG
,
/**< Detail for whoever is debugging. */
43
LOG_INFO
,
/**< Normal progress worth recording. The default level. */
44
LOG_WARN
,
/**< Something odd that the program survived. */
45
LOG_ERROR
,
/**< An operation failed. */
46
LOG_FATAL
,
/**< The program cannot continue. */
47
}
LogLevel
;
48
49
#ifndef LOG_LEVEL_MIN
50
/** Calls below this level compile to nothing. Define it before the first
51
* include of log.h, for example `-DLOG_LEVEL_MIN=LOG_INFO`. */
52
#define LOG_LEVEL_MIN LOG_TRACE
53
#endif
54
55
/** Drop messages below @p level from now on. */
56
void
log_set_level
(
LogLevel
level);
57
/** Write messages to @p f from now on. Null means stderr, the default. */
58
void
log_set_output
(FILE *f);
59
60
/** @} */
61
62
/** @name Logging
63
* Each macro takes a printf format and its arguments, which the compiler
64
* checks.
65
* @{ */
66
67
/** Log a printf-style message at LOG_TRACE. */
68
#define log_trace(...) LOG_AT_(LOG_TRACE, __VA_ARGS__)
69
/** Log a printf-style message at LOG_DEBUG. */
70
#define log_debug(...) LOG_AT_(LOG_DEBUG, __VA_ARGS__)
71
/** Log a printf-style message at LOG_INFO. */
72
#define log_info(...) LOG_AT_(LOG_INFO, __VA_ARGS__)
73
/** Log a printf-style message at LOG_WARN. */
74
#define log_warn(...) LOG_AT_(LOG_WARN, __VA_ARGS__)
75
/** Log a printf-style message at LOG_ERROR. */
76
#define log_error(...) LOG_AT_(LOG_ERROR, __VA_ARGS__)
77
/** Log a printf-style message at LOG_FATAL, flush, and abort. */
78
#define log_fatal(...) log_fatal_(__FILE__, __LINE__, __VA_ARGS__)
79
/** Abort through log_fatal() when @p cond is false. Unlike assert(), it stays
80
* in release builds. */
81
#define log_assert(cond) \
82
((cond) ? (void)0 \
83
: log_fatal_(__FILE__, __LINE__, "assertion failed: %s", #cond))
84
85
/** @} */
86
87
/** @name Colour
88
* Decide whether to colour output, and the escapes to do it with.
89
* @{ */
90
91
/** True when colour escapes written to @p f will render as colour. Reads the
92
* environment on every call, so call it once and keep the answer. */
93
MULE_NODISCARD
bool
log_color_enabled
(FILE *f);
94
95
/* ANSI escape sequences. Macros, so they join string literals:
96
* `LOG_GREEN "ok" LOG_RESET`. Print them only when log_color_enabled(). */
97
#define LOG_RED "\x1b[31m"
/**< Red text. */
98
#define LOG_GREEN "\x1b[32m"
/**< Green text. */
99
#define LOG_YELLOW "\x1b[33m"
/**< Yellow text. */
100
#define LOG_RESET "\x1b[0m"
/**< Back to the terminal's default style. */
101
102
/** @} */
103
104
/** @cond */
105
extern
LogLevel
log_level_;
106
107
#define LOG_AT_(level, ...) \
108
((level) >= LOG_LEVEL_MIN && (level) >= log_level_ \
109
? log_write_((level), __FILE__, __LINE__, __VA_ARGS__) \
110
: (void)0)
111
112
void
log_write_(
LogLevel
level,
const
char
*file,
int
line,
const
char
*fmt,
113
...) MULE_PRINTF(4, 5);
114
MULE_NORETURN
void
log_fatal_(const
char
*file,
int
line, const
char
*fmt, ...)
115
MULE_PRINTF(3, 4);
116
/** @endcond */
117
118
/** @} */
log_set_output
void log_set_output(FILE *f)
Write messages to f from now on.
Definition
log.c:26
log_set_level
void log_set_level(LogLevel level)
Drop messages below level from now on.
Definition
log.c:22
log_color_enabled
bool log_color_enabled(FILE *f)
True when colour escapes written to f will render as colour.
Definition
log.c:37
LogLevel
LogLevel
How much a message matters, from chattiest to most severe.
Definition
log.h:40
LOG_ERROR
@ LOG_ERROR
An operation failed.
Definition
log.h:45
LOG_TRACE
@ LOG_TRACE
Step-by-step detail, usually off.
Definition
log.h:41
LOG_INFO
@ LOG_INFO
Normal progress worth recording.
Definition
log.h:43
LOG_DEBUG
@ LOG_DEBUG
Detail for whoever is debugging.
Definition
log.h:42
LOG_FATAL
@ LOG_FATAL
The program cannot continue.
Definition
log.h:46
LOG_WARN
@ LOG_WARN
Something odd that the program survived.
Definition
log.h:44
src
log
log.h
Generated by
1.18.0