]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
c2f1db8f | 2 | #pragma once |
5899f3b7 | 3 | |
17a94911 | 4 | #include <stdarg.h> |
07630cea | 5 | #include <stdbool.h> |
6410074b | 6 | #include <stdlib.h> |
63275a70 | 7 | #include <string.h> |
07630cea | 8 | #include <syslog.h> |
5899f3b7 | 9 | |
7c7a9138 | 10 | #include "list.h" |
158350e8 | 11 | #include "macro.h" |
34683dbd | 12 | #include "ratelimit.h" |
7c7a9138 | 13 | #include "stdio-util.h" |
dccca82b LP |
14 | |
15 | /* Some structures we reference but don't want to pull in headers for */ | |
16 | struct iovec; | |
17 | struct signalfd_siginfo; | |
5899f3b7 | 18 | |
16801e90 LP |
19 | typedef enum LogTarget{ |
20 | LOG_TARGET_CONSOLE, | |
16801e90 | 21 | LOG_TARGET_KMSG, |
5ba081b0 | 22 | LOG_TARGET_JOURNAL, |
843d2643 | 23 | LOG_TARGET_SYSLOG, |
e8815abf DDM |
24 | LOG_TARGET_CONSOLE_PREFIXED, |
25 | LOG_TARGET_JOURNAL_OR_KMSG, | |
843d2643 | 26 | LOG_TARGET_SYSLOG_OR_KMSG, |
27ffec08 | 27 | LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */ |
9fae33d2 | 28 | LOG_TARGET_NULL, |
e8815abf DDM |
29 | _LOG_TARGET_SINGLE_MAX = LOG_TARGET_SYSLOG + 1, |
30 | _LOG_TARGET_MAX = LOG_TARGET_NULL + 1, | |
2d93c20e | 31 | _LOG_TARGET_INVALID = -EINVAL, |
ff524019 ZJS |
32 | } LogTarget; |
33 | ||
9c416180 | 34 | /* This log level disables logging completely. It can only be passed to log_set_max_level() and cannot be |
e55db9e7 | 35 | * used as a regular log level. */ |
9c416180 DDM |
36 | #define LOG_NULL (LOG_EMERG - 1) |
37 | ||
5f74fcd4 | 38 | /* Note to readers: << and >> have lower precedence (are evaluated earlier) than & and | */ |
52d86690 ZJS |
39 | #define SYNTHETIC_ERRNO(num) (1 << 30 | (num)) |
40 | #define IS_SYNTHETIC_ERRNO(val) ((val) >> 30 & 1) | |
5f74fcd4 | 41 | #define ERRNO_VALUE(val) (abs(val) & ~(1 << 30)) |
16801e90 | 42 | |
3cc3dc77 MG |
43 | /* The callback function to be invoked when syntax warnings are seen |
44 | * in the unit files. */ | |
45 | typedef void (*log_syntax_callback_t)(const char *unit, int level, void *userdata); | |
46 | void set_log_syntax_callback(log_syntax_callback_t cb, void *userdata); | |
47 | ||
48 | static inline void clear_log_syntax_callback(dummy_t *dummy) { | |
49 | set_log_syntax_callback(/* cb= */ NULL, /* userdata= */ NULL); | |
50 | } | |
51 | ||
9fdee66f YW |
52 | const char *log_target_to_string(LogTarget target) _const_; |
53 | LogTarget log_target_from_string(const char *s) _pure_; | |
16801e90 | 54 | void log_set_target(LogTarget target); |
1e344c1d | 55 | void log_set_target_and_open(LogTarget target); |
9fdee66f YW |
56 | int log_set_target_from_string(const char *e); |
57 | LogTarget log_get_target(void) _pure_; | |
a3b00f91 | 58 | void log_settle_target(void); |
1c36b8bf | 59 | |
9fdee66f YW |
60 | void log_set_max_level(int level); |
61 | int log_set_max_level_from_string(const char *e); | |
62 | int log_get_max_level(void) _pure_; | |
e8815abf | 63 | int log_max_levels_to_string(int level, char **ret); |
1c36b8bf | 64 | |
3eff4208 | 65 | void log_set_facility(int facility); |
16801e90 | 66 | |
bbe63281 | 67 | void log_show_color(bool b); |
b1e90ec5 | 68 | bool log_get_show_color(void) _pure_; |
bbe63281 | 69 | void log_show_location(bool b); |
b1e90ec5 | 70 | bool log_get_show_location(void) _pure_; |
c5673ed0 DS |
71 | void log_show_time(bool b); |
72 | bool log_get_show_time(void) _pure_; | |
9ee806d1 LP |
73 | void log_show_tid(bool b); |
74 | bool log_get_show_tid(void) _pure_; | |
bbe63281 LP |
75 | |
76 | int log_show_color_from_string(const char *e); | |
77 | int log_show_location_from_string(const char *e); | |
c5673ed0 | 78 | int log_show_time_from_string(const char *e); |
9ee806d1 | 79 | int log_show_tid_from_string(const char *e); |
bbe63281 | 80 | |
e3e42fc2 ZJS |
81 | /* Functions below that open and close logs or configure logging based on the |
82 | * environment should not be called from library code — this is always a job | |
9fdee66f | 83 | * for the application itself. */ |
e3e42fc2 | 84 | |
ab1a1ba5 | 85 | assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1); |
f455f863 | 86 | #define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1]) |
a0b15b41 | 87 | |
843d2643 | 88 | int log_open(void); |
871e5809 | 89 | void log_close(void); |
4d8a7798 | 90 | void log_forget_fds(void); |
843d2643 | 91 | |
a7d15a24 | 92 | void log_parse_environment_variables(void); |
9fdee66f | 93 | void log_parse_environment(void); |
34f0e866 | 94 | |
93484b47 ZJS |
95 | int log_dispatch_internal( |
96 | int level, | |
97 | int error, | |
98 | const char *file, | |
99 | int line, | |
100 | const char *func, | |
101 | const char *object_field, | |
102 | const char *object, | |
103 | const char *extra, | |
104 | const char *extra_field, | |
105 | char *buffer); | |
106 | ||
9fdee66f | 107 | int log_internal( |
877d54e9 | 108 | int level, |
086891e5 | 109 | int error, |
79008bdd | 110 | const char *file, |
877d54e9 LP |
111 | int line, |
112 | const char *func, | |
086891e5 | 113 | const char *format, ...) _printf_(6,7); |
5899f3b7 | 114 | |
9fdee66f | 115 | int log_internalv( |
877d54e9 | 116 | int level, |
086891e5 | 117 | int error, |
79008bdd | 118 | const char *file, |
877d54e9 LP |
119 | int line, |
120 | const char *func, | |
121 | const char *format, | |
086891e5 | 122 | va_list ap) _printf_(6,0); |
877d54e9 | 123 | |
f6d6d532 YW |
124 | int log_object_internalv( |
125 | int level, | |
126 | int error, | |
127 | const char *file, | |
128 | int line, | |
129 | const char *func, | |
130 | const char *object_field, | |
131 | const char *object, | |
132 | const char *extra_field, | |
133 | const char *extra, | |
134 | const char *format, | |
135 | va_list ap) _printf_(10,0); | |
136 | ||
79008bdd | 137 | int log_object_internal( |
fdf9f9bb | 138 | int level, |
086891e5 | 139 | int error, |
79008bdd | 140 | const char *file, |
fdf9f9bb ZJS |
141 | int line, |
142 | const char *func, | |
79008bdd | 143 | const char *object_field, |
fdf9f9bb | 144 | const char *object, |
4b58153d LP |
145 | const char *extra_field, |
146 | const char *extra, | |
147 | const char *format, ...) _printf_(10,11); | |
fdf9f9bb | 148 | |
877d54e9 LP |
149 | int log_struct_internal( |
150 | int level, | |
086891e5 | 151 | int error, |
877d54e9 LP |
152 | const char *file, |
153 | int line, | |
154 | const char *func, | |
086891e5 | 155 | const char *format, ...) _printf_(6,0) _sentinel_; |
877d54e9 LP |
156 | |
157 | int log_oom_internal( | |
b3a79158 | 158 | int level, |
877d54e9 LP |
159 | const char *file, |
160 | int line, | |
161 | const char *func); | |
185986c6 | 162 | |
8a03c9ef ZJS |
163 | int log_format_iovec( |
164 | struct iovec *iovec, | |
d3070fbd LP |
165 | size_t iovec_len, |
166 | size_t *n, | |
8a03c9ef ZJS |
167 | bool newline_separator, |
168 | int error, | |
169 | const char *format, | |
ba360bb0 | 170 | va_list ap) _printf_(6, 0); |
8a03c9ef | 171 | |
915b1d01 LP |
172 | int log_struct_iovec_internal( |
173 | int level, | |
174 | int error, | |
175 | const char *file, | |
176 | int line, | |
177 | const char *func, | |
dccca82b | 178 | const struct iovec *input_iovec, |
915b1d01 LP |
179 | size_t n_input_iovec); |
180 | ||
2149e37c LP |
181 | /* This modifies the buffer passed! */ |
182 | int log_dump_internal( | |
877d54e9 | 183 | int level, |
086891e5 | 184 | int error, |
79008bdd | 185 | const char *file, |
877d54e9 LP |
186 | int line, |
187 | const char *func, | |
188 | char *buffer); | |
189 | ||
086891e5 | 190 | /* Logging for various assertions */ |
9fdee66f | 191 | _noreturn_ void log_assert_failed( |
877d54e9 LP |
192 | const char *text, |
193 | const char *file, | |
194 | int line, | |
195 | const char *func); | |
196 | ||
9fdee66f | 197 | _noreturn_ void log_assert_failed_unreachable( |
877d54e9 LP |
198 | const char *file, |
199 | int line, | |
200 | const char *func); | |
80514f9c | 201 | |
9fdee66f | 202 | void log_assert_failed_return( |
80514f9c LP |
203 | const char *text, |
204 | const char *file, | |
205 | int line, | |
206 | const char *func); | |
2149e37c | 207 | |
93484b47 | 208 | #define log_dispatch(level, error, buffer) \ |
62c6bbbc | 209 | log_dispatch_internal(level, error, PROJECT_FILE, __LINE__, __func__, NULL, NULL, NULL, NULL, buffer) |
93484b47 | 210 | |
086891e5 | 211 | /* Logging with level */ |
a626cb15 | 212 | #define log_full_errno_zerook(level, error, ...) \ |
1cfa9a4c | 213 | ({ \ |
5df4f46f | 214 | int _level = (level), _e = (error); \ |
cbe97b9c | 215 | _e = (log_get_max_level() >= LOG_PRI(_level)) \ |
5df4f46f | 216 | ? log_internal(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ |
baaa35ad | 217 | : -ERRNO_VALUE(_e); \ |
59e8042e | 218 | _e < 0 ? _e : -ESTRPIPE; \ |
bf371116 | 219 | }) |
87ff6b1c | 220 | |
a626cb15 ZJS |
221 | #if BUILD_MODE_DEVELOPER && !defined(TEST_CODE) |
222 | # define ASSERT_NON_ZERO(x) assert((x) != 0) | |
223 | #else | |
224 | # define ASSERT_NON_ZERO(x) | |
225 | #endif | |
226 | ||
227 | #define log_full_errno(level, error, ...) \ | |
228 | ({ \ | |
229 | int _error = (error); \ | |
230 | ASSERT_NON_ZERO(_error); \ | |
231 | log_full_errno_zerook(level, _error, __VA_ARGS__); \ | |
232 | }) | |
233 | ||
63275a70 ZJS |
234 | #define log_full(level, fmt, ...) \ |
235 | ({ \ | |
236 | if (BUILD_MODE_DEVELOPER) \ | |
237 | assert(!strstr(fmt, "%m")); \ | |
a626cb15 | 238 | (void) log_full_errno_zerook(level, 0, fmt, ##__VA_ARGS__); \ |
63275a70 | 239 | }) |
086891e5 | 240 | |
dccca82b LP |
241 | int log_emergency_level(void); |
242 | ||
086891e5 | 243 | /* Normal logging */ |
75029e15 | 244 | #define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) |
4104970e ZJS |
245 | #define log_info(...) log_full(LOG_INFO, __VA_ARGS__) |
246 | #define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) | |
247 | #define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) | |
248 | #define log_error(...) log_full(LOG_ERR, __VA_ARGS__) | |
dccca82b | 249 | #define log_emergency(...) log_full(log_emergency_level(), __VA_ARGS__) |
5899f3b7 | 250 | |
086891e5 LP |
251 | /* Logging triggered by an errno-like error */ |
252 | #define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__) | |
253 | #define log_info_errno(error, ...) log_full_errno(LOG_INFO, error, __VA_ARGS__) | |
254 | #define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__) | |
255 | #define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__) | |
256 | #define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__) | |
dccca82b | 257 | #define log_emergency_errno(error, ...) log_full_errno(log_emergency_level(), error, __VA_ARGS__) |
086891e5 | 258 | |
264f0afe DS |
259 | /* This logs at the specified level the first time it is called, and then |
260 | * logs at debug. If the specified level is debug, this logs only the first | |
261 | * time it is called. */ | |
262 | #define log_once(level, ...) \ | |
263 | ({ \ | |
264 | if (ONCE) \ | |
265 | log_full(level, __VA_ARGS__); \ | |
266 | else if (LOG_PRI(level) != LOG_DEBUG) \ | |
267 | log_debug(__VA_ARGS__); \ | |
268 | }) | |
269 | ||
270 | #define log_once_errno(level, error, ...) \ | |
271 | ({ \ | |
272 | int _err = (error); \ | |
273 | if (ONCE) \ | |
274 | _err = log_full_errno(level, _err, __VA_ARGS__); \ | |
275 | else if (LOG_PRI(level) != LOG_DEBUG) \ | |
276 | _err = log_debug_errno(_err, __VA_ARGS__); \ | |
277 | else \ | |
278 | _err = -ERRNO_VALUE(_err); \ | |
279 | _err; \ | |
280 | }) | |
281 | ||
e355fb6f | 282 | #if LOG_TRACE |
68a2ed61 YW |
283 | # define log_trace(...) log_debug(__VA_ARGS__) |
284 | # define log_trace_errno(...) log_debug_errno(__VA_ARGS__) | |
cb41ff29 | 285 | #else |
68a2ed61 YW |
286 | # define log_trace(...) do {} while (0) |
287 | # define log_trace_errno(e, ...) (-ERRNO_VALUE(e)) | |
cb41ff29 ZJS |
288 | #endif |
289 | ||
086891e5 | 290 | /* Structured logging */ |
9fdee66f YW |
291 | #define log_struct_errno(level, error, ...) \ |
292 | log_struct_internal(level, error, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__, NULL) | |
ff524019 | 293 | #define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__) |
0d0f0c50 | 294 | |
915b1d01 | 295 | #define log_struct_iovec_errno(level, error, iovec, n_iovec) \ |
9fdee66f | 296 | log_struct_iovec_internal(level, error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec) |
915b1d01 LP |
297 | #define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec) |
298 | ||
2149e37c | 299 | /* This modifies the buffer passed! */ |
9fdee66f YW |
300 | #define log_dump(level, buffer) \ |
301 | log_dump_internal(level, 0, PROJECT_FILE, __LINE__, __func__, buffer) | |
086891e5 | 302 | |
9fdee66f YW |
303 | #define log_oom() log_oom_internal(LOG_ERR, PROJECT_FILE, __LINE__, __func__) |
304 | #define log_oom_debug() log_oom_internal(LOG_DEBUG, PROJECT_FILE, __LINE__, __func__) | |
4453ebe4 | 305 | #define log_oom_warning() log_oom_internal(LOG_WARNING, PROJECT_FILE, __LINE__, __func__) |
2149e37c | 306 | |
44a6b1b6 | 307 | bool log_on_console(void) _pure_; |
81270860 | 308 | |
92663a5e ZJS |
309 | /* Helper to wrap the main message in structured logging. The macro doesn't do much, |
310 | * except to provide visual grouping of the format string and its arguments. */ | |
1ec7c156 | 311 | #if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__) |
011a03a3 ZJS |
312 | /* Do a fake formatting of the message string to let the scanner verify the arguments against the format |
313 | * message. The variable will never be set to true, but we don't tell the compiler that :) */ | |
314 | extern bool _log_message_dummy; | |
315 | # define LOG_MESSAGE(fmt, ...) "MESSAGE=%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__ | |
b9ce5cf9 ZJS |
316 | #else |
317 | # define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ | |
318 | #endif | |
4daf54a8 ZJS |
319 | |
320 | void log_received_signal(int level, const struct signalfd_siginfo *si); | |
c1dc6153 | 321 | |
6fdb8de4 | 322 | /* If turned on, any requests for a log target involving "syslog" will be implicitly upgraded to the equivalent journal target */ |
c1dc6153 | 323 | void log_set_upgrade_syslog_to_journal(bool b); |
7a3be263 LP |
324 | |
325 | /* If turned on, and log_open() is called, we'll not use STDERR_FILENO for logging ever, but rather open /dev/console */ | |
48a601fe | 326 | void log_set_always_reopen_console(bool b); |
7a3be263 LP |
327 | |
328 | /* If turned on, we'll open the log stream implicitly if needed on each individual log call. This is normally not | |
329 | * desired as we want to reuse our logging streams. It is useful however */ | |
16e4fd87 | 330 | void log_set_open_when_needed(bool b); |
158350e8 | 331 | |
adf47c91 LP |
332 | /* If turned on, then we'll never use IPC-based logging, i.e. never log to syslog or the journal. We'll only log to |
333 | * stderr, the console or kmsg */ | |
334 | void log_set_prohibit_ipc(bool b); | |
335 | ||
93bb6709 YW |
336 | void log_set_assert_return_is_critical(bool b); |
337 | bool log_get_assert_return_is_critical(void) _pure_; | |
338 | ||
17cac366 LP |
339 | int log_dup_console(void); |
340 | ||
158350e8 LP |
341 | int log_syntax_internal( |
342 | const char *unit, | |
343 | int level, | |
344 | const char *config_file, | |
345 | unsigned config_line, | |
346 | int error, | |
347 | const char *file, | |
348 | int line, | |
349 | const char *func, | |
350 | const char *format, ...) _printf_(9, 10); | |
351 | ||
d04ce5a9 LP |
352 | int log_syntax_invalid_utf8_internal( |
353 | const char *unit, | |
354 | int level, | |
355 | const char *config_file, | |
356 | unsigned config_line, | |
357 | const char *file, | |
358 | int line, | |
359 | const char *func, | |
360 | const char *rvalue); | |
361 | ||
158350e8 LP |
362 | #define log_syntax(unit, level, config_file, config_line, error, ...) \ |
363 | ({ \ | |
364 | int _level = (level), _e = (error); \ | |
365 | (log_get_max_level() >= LOG_PRI(_level)) \ | |
62c6bbbc | 366 | ? log_syntax_internal(unit, _level, config_file, config_line, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ |
ee96382f | 367 | : -ERRNO_VALUE(_e); \ |
158350e8 | 368 | }) |
0e05ee04 LP |
369 | |
370 | #define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ | |
371 | ({ \ | |
372 | int _level = (level); \ | |
d04ce5a9 | 373 | (log_get_max_level() >= LOG_PRI(_level)) \ |
62c6bbbc | 374 | ? log_syntax_invalid_utf8_internal(unit, _level, config_file, config_line, PROJECT_FILE, __LINE__, __func__, rvalue) \ |
d04ce5a9 | 375 | : -EINVAL; \ |
0e05ee04 | 376 | }) |
f1d34068 LP |
377 | |
378 | #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG) | |
6bf3c61c | 379 | |
d2acb93d | 380 | void log_setup(void); |
34683dbd RP |
381 | |
382 | typedef struct LogRateLimit { | |
383 | int error; | |
384 | int level; | |
385 | RateLimit ratelimit; | |
386 | } LogRateLimit; | |
387 | ||
4dcfdd21 | 388 | #define log_ratelimit_internal(_level, _error, _ratelimit, _file, _line, _func, _format, ...) \ |
34683dbd RP |
389 | ({ \ |
390 | int _log_ratelimit_error = (_error); \ | |
391 | int _log_ratelimit_level = (_level); \ | |
392 | static LogRateLimit _log_ratelimit = { \ | |
0f06e64c | 393 | .ratelimit = (_ratelimit), \ |
34683dbd RP |
394 | }; \ |
395 | unsigned _num_dropped_errors = ratelimit_num_dropped(&_log_ratelimit.ratelimit); \ | |
396 | if (_log_ratelimit_error != _log_ratelimit.error || _log_ratelimit_level != _log_ratelimit.level) { \ | |
397 | ratelimit_reset(&_log_ratelimit.ratelimit); \ | |
398 | _log_ratelimit.error = _log_ratelimit_error; \ | |
399 | _log_ratelimit.level = _log_ratelimit_level; \ | |
400 | } \ | |
a423050e | 401 | if (log_get_max_level() == LOG_DEBUG || ratelimit_below(&_log_ratelimit.ratelimit)) \ |
34683dbd | 402 | _log_ratelimit_error = _num_dropped_errors > 0 \ |
fa83506d DDM |
403 | ? log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format " (Dropped %u similar message(s))", ##__VA_ARGS__, _num_dropped_errors) \ |
404 | : log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format, ##__VA_ARGS__); \ | |
34683dbd RP |
405 | _log_ratelimit_error; \ |
406 | }) | |
407 | ||
0f06e64c | 408 | #define log_ratelimit_full_errno(level, error, _ratelimit, format, ...) \ |
34683dbd RP |
409 | ({ \ |
410 | int _level = (level), _e = (error); \ | |
411 | _e = (log_get_max_level() >= LOG_PRI(_level)) \ | |
4dcfdd21 | 412 | ? log_ratelimit_internal(_level, _e, _ratelimit, PROJECT_FILE, __LINE__, __func__, format, ##__VA_ARGS__) \ |
34683dbd RP |
413 | : -ERRNO_VALUE(_e); \ |
414 | _e < 0 ? _e : -ESTRPIPE; \ | |
415 | }) | |
7a2ec6d0 | 416 | |
0f06e64c DDM |
417 | #define log_ratelimit_full(level, _ratelimit, format, ...) \ |
418 | log_ratelimit_full_errno(level, 0, _ratelimit, format, ##__VA_ARGS__) | |
2199ff90 DDM |
419 | |
420 | /* Normal logging */ | |
2199ff90 DDM |
421 | #define log_ratelimit_info(...) log_ratelimit_full(LOG_INFO, __VA_ARGS__) |
422 | #define log_ratelimit_notice(...) log_ratelimit_full(LOG_NOTICE, __VA_ARGS__) | |
423 | #define log_ratelimit_warning(...) log_ratelimit_full(LOG_WARNING, __VA_ARGS__) | |
424 | #define log_ratelimit_error(...) log_ratelimit_full(LOG_ERR, __VA_ARGS__) | |
425 | #define log_ratelimit_emergency(...) log_ratelimit_full(log_emergency_level(), __VA_ARGS__) | |
426 | ||
427 | /* Logging triggered by an errno-like error */ | |
2199ff90 DDM |
428 | #define log_ratelimit_info_errno(error, ...) log_ratelimit_full_errno(LOG_INFO, error, __VA_ARGS__) |
429 | #define log_ratelimit_notice_errno(error, ...) log_ratelimit_full_errno(LOG_NOTICE, error, __VA_ARGS__) | |
430 | #define log_ratelimit_warning_errno(error, ...) log_ratelimit_full_errno(LOG_WARNING, error, __VA_ARGS__) | |
431 | #define log_ratelimit_error_errno(error, ...) log_ratelimit_full_errno(LOG_ERR, error, __VA_ARGS__) | |
432 | #define log_ratelimit_emergency_errno(error, ...) log_ratelimit_full_errno(log_emergency_level(), error, __VA_ARGS__) | |
7c7a9138 | 433 | |
ee2975a9 DDM |
434 | const char *_log_set_prefix(const char *prefix, bool force); |
435 | static inline const char *_log_unset_prefixp(const char **p) { | |
436 | assert(p); | |
437 | _log_set_prefix(*p, true); | |
438 | return NULL; | |
439 | } | |
440 | ||
441 | #define LOG_SET_PREFIX(prefix) \ | |
442 | _cleanup_(_log_unset_prefixp) _unused_ const char *CONCATENATE(_cleanup_log_unset_prefix_, UNIQ) = _log_set_prefix(prefix, false); | |
443 | ||
7c7a9138 DDM |
444 | /* |
445 | * The log context allows attaching extra metadata to log messages written to the journal via log.h. We keep | |
446 | * track of a thread local log context onto which we can push extra metadata fields that should be logged. | |
447 | * | |
448 | * LOG_CONTEXT_PUSH() will add the provided field to the log context and will remove it again when the | |
449 | * current block ends. LOG_CONTEXT_PUSH_STRV() will do the same but for all fields in the given strv. | |
450 | * LOG_CONTEXT_PUSHF() is like LOG_CONTEXT_PUSH() but takes a format string and arguments. | |
451 | * | |
452 | * Using the macros is as simple as putting them anywhere inside a block to add a field to all following log | |
453 | * messages logged from inside that block. | |
454 | * | |
455 | * void myfunction(...) { | |
456 | * ... | |
457 | * | |
458 | * LOG_CONTEXT_PUSHF("MYMETADATA=%s", "abc"); | |
459 | * | |
460 | * // Every journal message logged will now have the MYMETADATA=abc | |
461 | * // field included. | |
462 | * } | |
463 | * | |
464 | * One special case to note is async code, where we use callbacks that are invoked to continue processing | |
465 | * when some event occurs. For async code, there's usually an associated "userdata" struct containing all the | |
466 | * information associated with the async operation. In this "userdata" struct, we can store a log context | |
467 | * allocated with log_context_new() and freed with log_context_free(). We can then add and remove fields to | |
468 | * the `fields` member of the log context object and all those fields will be logged along with each log | |
469 | * message. | |
470 | */ | |
471 | ||
472 | typedef struct LogContext LogContext; | |
473 | ||
474 | bool log_context_enabled(void); | |
475 | ||
81b3565e DDM |
476 | LogContext* log_context_new(const char *key, const char *value); |
477 | LogContext* log_context_new_strv(char **fields, bool owned); | |
478 | LogContext* log_context_new_iov(struct iovec *input_iovec, size_t n_input_iovec, bool owned); | |
7c7a9138 | 479 | |
2461943b | 480 | /* Same as log_context_new(), but frees the given fields strv/iovec on failure. */ |
81b3565e DDM |
481 | LogContext* log_context_new_strv_consume(char **fields); |
482 | LogContext* log_context_new_iov_consume(struct iovec *input_iovec, size_t n_input_iovec); | |
7c7a9138 | 483 | |
88335453 DDM |
484 | LogContext *log_context_ref(LogContext *c); |
485 | LogContext *log_context_unref(LogContext *c); | |
486 | ||
487 | DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_unref); | |
7c7a9138 DDM |
488 | |
489 | /* Returns the number of attached log context objects. */ | |
490 | size_t log_context_num_contexts(void); | |
491 | /* Returns the number of fields in all attached log contexts. */ | |
492 | size_t log_context_num_fields(void); | |
493 | ||
7c7a9138 DDM |
494 | #define LOG_CONTEXT_PUSH(...) \ |
495 | LOG_CONTEXT_PUSH_STRV(STRV_MAKE(__VA_ARGS__)) | |
496 | ||
497 | #define LOG_CONTEXT_PUSHF(...) \ | |
498 | LOG_CONTEXT_PUSH(snprintf_ok((char[LINE_MAX]) {}, LINE_MAX, __VA_ARGS__)) | |
499 | ||
81b3565e DDM |
500 | #define _LOG_CONTEXT_PUSH_KEY_VALUE(key, value, c) \ |
501 | _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new(key, value); | |
502 | ||
503 | #define LOG_CONTEXT_PUSH_KEY_VALUE(key, value) \ | |
504 | _LOG_CONTEXT_PUSH_KEY_VALUE(key, value, UNIQ_T(c, UNIQ)) | |
505 | ||
7c7a9138 | 506 | #define _LOG_CONTEXT_PUSH_STRV(strv, c) \ |
81b3565e | 507 | _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv(strv, /*owned=*/ false); |
7c7a9138 DDM |
508 | |
509 | #define LOG_CONTEXT_PUSH_STRV(strv) \ | |
510 | _LOG_CONTEXT_PUSH_STRV(strv, UNIQ_T(c, UNIQ)) | |
511 | ||
2461943b | 512 | #define _LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec, c) \ |
81b3565e | 513 | _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_iov(input_iovec, n_input_iovec, /*owned=*/ false); |
2461943b LB |
514 | |
515 | #define LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec) \ | |
516 | _LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec, UNIQ_T(c, UNIQ)) | |
517 | ||
518 | /* LOG_CONTEXT_CONSUME_STR()/LOG_CONTEXT_CONSUME_STRV()/LOG_CONTEXT_CONSUME_IOV() are identical to | |
519 | * LOG_CONTEXT_PUSH_STR()/LOG_CONTEXT_PUSH_STRV()/LOG_CONTEXT_PUSH_IOV() except they take ownership of the | |
520 | * given str/strv argument. | |
7c7a9138 DDM |
521 | */ |
522 | ||
523 | #define _LOG_CONTEXT_CONSUME_STR(s, c, strv) \ | |
524 | _unused_ _cleanup_strv_free_ strv = strv_new(s); \ | |
525 | if (!strv) \ | |
526 | free(s); \ | |
81b3565e | 527 | _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv_consume(TAKE_PTR(strv)) |
7c7a9138 DDM |
528 | |
529 | #define LOG_CONTEXT_CONSUME_STR(s) \ | |
530 | _LOG_CONTEXT_CONSUME_STR(s, UNIQ_T(c, UNIQ), UNIQ_T(sv, UNIQ)) | |
531 | ||
532 | #define _LOG_CONTEXT_CONSUME_STRV(strv, c) \ | |
81b3565e | 533 | _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv_consume(strv); |
7c7a9138 DDM |
534 | |
535 | #define LOG_CONTEXT_CONSUME_STRV(strv) \ | |
536 | _LOG_CONTEXT_CONSUME_STRV(strv, UNIQ_T(c, UNIQ)) | |
2461943b LB |
537 | |
538 | #define _LOG_CONTEXT_CONSUME_IOV(input_iovec, n_input_iovec, c) \ | |
81b3565e | 539 | _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_iov_consume(input_iovec, n_input_iovec); |
2461943b LB |
540 | |
541 | #define LOG_CONTEXT_CONSUME_IOV(input_iovec, n_input_iovec) \ | |
542 | _LOG_CONTEXT_CONSUME_IOV(input_iovec, n_input_iovec, UNIQ_T(c, UNIQ)) |