]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | #pragma once | |
3 | ||
4 | #include <stdio.h> | |
5 | #include <string.h> | |
6 | #include <syslog.h> | |
7 | ||
8 | #include "forward.h" | |
9 | ||
10 | typedef enum LogTarget{ | |
11 | LOG_TARGET_CONSOLE, | |
12 | LOG_TARGET_KMSG, | |
13 | LOG_TARGET_JOURNAL, | |
14 | LOG_TARGET_SYSLOG, | |
15 | LOG_TARGET_CONSOLE_PREFIXED, | |
16 | LOG_TARGET_JOURNAL_OR_KMSG, | |
17 | LOG_TARGET_SYSLOG_OR_KMSG, | |
18 | LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */ | |
19 | LOG_TARGET_NULL, | |
20 | _LOG_TARGET_SINGLE_MAX = LOG_TARGET_SYSLOG + 1, | |
21 | _LOG_TARGET_MAX = LOG_TARGET_NULL + 1, | |
22 | _LOG_TARGET_INVALID = -EINVAL, | |
23 | } LogTarget; | |
24 | ||
25 | /* This log level disables logging completely. It can only be passed to log_set_max_level() and cannot be | |
26 | * used as a regular log level. */ | |
27 | #define LOG_NULL (LOG_EMERG - 1) | |
28 | assert_cc(LOG_NULL == -1); | |
29 | ||
30 | #define SYNTHETIC_ERRNO(num) (ABS(num) | (1 << 30)) | |
31 | #define IS_SYNTHETIC_ERRNO(val) (((val) >> 30) == 1) | |
32 | #define ERRNO_VALUE(val) (ABS(val) & ~(1 << 30)) | |
33 | ||
34 | /* The callback function to be invoked when syntax warnings are seen | |
35 | * in the unit files. */ | |
36 | typedef void (*log_syntax_callback_t)(const char *unit, int level, void *userdata); | |
37 | void set_log_syntax_callback(log_syntax_callback_t cb, void *userdata); | |
38 | ||
39 | static inline void clear_log_syntax_callback(dummy_t *dummy) { | |
40 | set_log_syntax_callback(/* cb= */ NULL, /* userdata= */ NULL); | |
41 | } | |
42 | ||
43 | const char* log_target_to_string(LogTarget target) _const_; | |
44 | LogTarget log_target_from_string(const char *s) _pure_; | |
45 | void log_set_target(LogTarget target); | |
46 | void log_set_target_and_open(LogTarget target); | |
47 | int log_set_target_from_string(const char *e); | |
48 | LogTarget log_get_target(void) _pure_; | |
49 | void log_settle_target(void); | |
50 | ||
51 | int log_set_max_level(int level); | |
52 | int log_set_max_level_from_string(const char *e); | |
53 | int log_get_max_level(void) _pure_; | |
54 | int log_get_target_max_level(LogTarget target); | |
55 | int log_max_levels_to_string(int level, char **ret); | |
56 | ||
57 | void log_set_facility(int facility); | |
58 | ||
59 | void log_show_color(bool b); | |
60 | bool log_get_show_color(void) _pure_; | |
61 | void log_show_location(bool b); | |
62 | bool log_get_show_location(void) _pure_; | |
63 | void log_show_time(bool b); | |
64 | bool log_get_show_time(void) _pure_; | |
65 | void log_show_tid(bool b); | |
66 | bool log_get_show_tid(void) _pure_; | |
67 | ||
68 | int log_show_color_from_string(const char *e); | |
69 | int log_show_location_from_string(const char *e); | |
70 | int log_show_time_from_string(const char *e); | |
71 | int log_show_tid_from_string(const char *e); | |
72 | ||
73 | /* Functions below that open and close logs or configure logging based on the | |
74 | * environment should not be called from library code — this is always a job | |
75 | * for the application itself. */ | |
76 | ||
77 | bool stderr_is_journal(void); | |
78 | int log_open(void); | |
79 | void log_close(void); | |
80 | void log_forget_fds(void); | |
81 | ||
82 | void log_parse_environment_variables(void); | |
83 | void log_parse_environment(void); | |
84 | ||
85 | int log_dispatch_internal( | |
86 | int level, | |
87 | int error, | |
88 | const char *file, | |
89 | int line, | |
90 | const char *func, | |
91 | const char *object_field, | |
92 | const char *object, | |
93 | const char *extra_field, | |
94 | const char *extra, | |
95 | char *buffer); | |
96 | ||
97 | int log_internal( | |
98 | int level, | |
99 | int error, | |
100 | const char *file, | |
101 | int line, | |
102 | const char *func, | |
103 | const char *format, ...) _printf_(6,7); | |
104 | ||
105 | int log_internalv( | |
106 | int level, | |
107 | int error, | |
108 | const char *file, | |
109 | int line, | |
110 | const char *func, | |
111 | const char *format, | |
112 | va_list ap) _printf_(6,0); | |
113 | ||
114 | int log_object_internalv( | |
115 | int level, | |
116 | int error, | |
117 | const char *file, | |
118 | int line, | |
119 | const char *func, | |
120 | const char *object_field, | |
121 | const char *object, | |
122 | const char *extra_field, | |
123 | const char *extra, | |
124 | const char *format, | |
125 | va_list ap) _printf_(10,0); | |
126 | ||
127 | int log_object_internal( | |
128 | int level, | |
129 | int error, | |
130 | const char *file, | |
131 | int line, | |
132 | const char *func, | |
133 | const char *object_field, | |
134 | const char *object, | |
135 | const char *extra_field, | |
136 | const char *extra, | |
137 | const char *format, ...) _printf_(10,11); | |
138 | ||
139 | int log_struct_internal( | |
140 | int level, | |
141 | int error, | |
142 | const char *file, | |
143 | int line, | |
144 | const char *func, | |
145 | const char *format, ...) _sentinel_; | |
146 | ||
147 | int log_oom_internal( | |
148 | int level, | |
149 | const char *file, | |
150 | int line, | |
151 | const char *func); | |
152 | ||
153 | int log_format_iovec( | |
154 | struct iovec *iovec, | |
155 | size_t iovec_len, | |
156 | size_t *n, | |
157 | bool newline_separator, | |
158 | int error, | |
159 | const char *format, | |
160 | va_list ap) _printf_(6, 0); | |
161 | ||
162 | int log_struct_iovec_internal( | |
163 | int level, | |
164 | int error, | |
165 | const char *file, | |
166 | int line, | |
167 | const char *func, | |
168 | const struct iovec *input_iovec, | |
169 | size_t n_input_iovec); | |
170 | ||
171 | /* This modifies the buffer passed! */ | |
172 | int log_dump_internal( | |
173 | int level, | |
174 | int error, | |
175 | const char *file, | |
176 | int line, | |
177 | const char *func, | |
178 | char *buffer); | |
179 | ||
180 | #define log_dispatch(level, error, buffer) \ | |
181 | log_dispatch_internal(level, error, PROJECT_FILE, __LINE__, __func__, NULL, NULL, NULL, NULL, buffer) | |
182 | ||
183 | /* Logging with level */ | |
184 | #define log_full_errno_zerook(level, error, ...) \ | |
185 | ({ \ | |
186 | int _level = (level), _e = (error); \ | |
187 | _e = (log_get_max_level() >= LOG_PRI(_level)) \ | |
188 | ? log_internal(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ | |
189 | : -ERRNO_VALUE(_e); \ | |
190 | _e < 0 ? _e : -ESTRPIPE; \ | |
191 | }) | |
192 | ||
193 | #if BUILD_MODE_DEVELOPER && !defined(TEST_CODE) | |
194 | # define ASSERT_NON_ZERO(x) assert((x) != 0) | |
195 | #else | |
196 | # define ASSERT_NON_ZERO(x) | |
197 | #endif | |
198 | ||
199 | #define log_full_errno(level, error, ...) \ | |
200 | ({ \ | |
201 | int _error = (error); \ | |
202 | ASSERT_NON_ZERO(_error); \ | |
203 | log_full_errno_zerook(level, _error, __VA_ARGS__); \ | |
204 | }) | |
205 | ||
206 | #define log_full(level, fmt, ...) \ | |
207 | ({ \ | |
208 | if (BUILD_MODE_DEVELOPER) \ | |
209 | assert(!strstr(fmt, "%m")); \ | |
210 | (void) log_full_errno_zerook(level, 0, fmt, ##__VA_ARGS__); \ | |
211 | }) | |
212 | ||
213 | int log_emergency_level(void); | |
214 | ||
215 | /* Normal logging */ | |
216 | #define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) | |
217 | #define log_info(...) log_full(LOG_INFO, __VA_ARGS__) | |
218 | #define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) | |
219 | #define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) | |
220 | #define log_error(...) log_full(LOG_ERR, __VA_ARGS__) | |
221 | #define log_emergency(...) log_full(log_emergency_level(), __VA_ARGS__) | |
222 | ||
223 | /* Logging triggered by an errno-like error */ | |
224 | #define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__) | |
225 | #define log_info_errno(error, ...) log_full_errno(LOG_INFO, error, __VA_ARGS__) | |
226 | #define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__) | |
227 | #define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__) | |
228 | #define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__) | |
229 | #define log_emergency_errno(error, ...) log_full_errno(log_emergency_level(), error, __VA_ARGS__) | |
230 | ||
231 | /* This logs at the specified level the first time it is called, and then | |
232 | * logs at debug. If the specified level is debug, this logs only the first | |
233 | * time it is called. */ | |
234 | #define log_once(level, ...) \ | |
235 | ({ \ | |
236 | if (ONCE) \ | |
237 | log_full(level, __VA_ARGS__); \ | |
238 | else if (LOG_PRI(level) != LOG_DEBUG) \ | |
239 | log_debug(__VA_ARGS__); \ | |
240 | }) | |
241 | ||
242 | #define log_once_errno(level, error, ...) \ | |
243 | ({ \ | |
244 | int _err = (error); \ | |
245 | if (ONCE) \ | |
246 | _err = log_full_errno(level, _err, __VA_ARGS__); \ | |
247 | else if (LOG_PRI(level) != LOG_DEBUG) \ | |
248 | _err = log_debug_errno(_err, __VA_ARGS__); \ | |
249 | else \ | |
250 | _err = -ERRNO_VALUE(_err); \ | |
251 | _err; \ | |
252 | }) | |
253 | ||
254 | #if LOG_TRACE | |
255 | # define log_trace(...) log_debug(__VA_ARGS__) | |
256 | # define log_trace_errno(...) log_debug_errno(__VA_ARGS__) | |
257 | #else | |
258 | # define log_trace(...) do {} while (0) | |
259 | # define log_trace_errno(e, ...) (-ERRNO_VALUE(e)) | |
260 | #endif | |
261 | ||
262 | /* Structured logging */ | |
263 | #define log_struct_errno(level, error, ...) \ | |
264 | log_struct_internal(level, error, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__, NULL) | |
265 | #define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__) | |
266 | ||
267 | #define log_struct_iovec_errno(level, error, iovec, n_iovec) \ | |
268 | log_struct_iovec_internal(level, error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec) | |
269 | #define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec) | |
270 | ||
271 | /* This modifies the buffer passed! */ | |
272 | #define log_dump(level, buffer) \ | |
273 | log_dump_internal(level, 0, PROJECT_FILE, __LINE__, __func__, buffer) | |
274 | ||
275 | #define log_oom_full(level) log_oom_internal(level, PROJECT_FILE, __LINE__, __func__) | |
276 | #define log_oom() log_oom_full(LOG_ERR) | |
277 | #define log_oom_debug() log_oom_full(LOG_DEBUG) | |
278 | #define log_oom_warning() log_oom_full(LOG_WARNING) | |
279 | ||
280 | bool log_on_console(void) _pure_; | |
281 | ||
282 | /* Helper to wrap the main message in structured logging. The macro doesn't do much, | |
283 | * except to provide visual grouping of the format string and its arguments. */ | |
284 | #if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__) | |
285 | /* Do a fake formatting of the message string to let the scanner verify the arguments against the format | |
286 | * message. The variable will never be set to true, but we don't tell the compiler that :) */ | |
287 | extern bool _log_message_dummy; | |
288 | # define LOG_ITEM(fmt, ...) "%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__ | |
289 | # define LOG_MESSAGE(fmt, ...) LOG_ITEM("MESSAGE=" fmt, ##__VA_ARGS__) | |
290 | #else | |
291 | # define LOG_ITEM(fmt, ...) fmt, ##__VA_ARGS__ | |
292 | # define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ | |
293 | #endif | |
294 | ||
295 | #define LOG_MESSAGE_ID(id) LOG_ITEM("MESSAGE_ID=" id) | |
296 | ||
297 | void log_received_signal(int level, const struct signalfd_siginfo *si); | |
298 | ||
299 | /* If turned on, any requests for a log target involving "syslog" will be implicitly upgraded to the equivalent journal target */ | |
300 | void log_set_upgrade_syslog_to_journal(bool b); | |
301 | ||
302 | /* If turned on, and log_open() is called, we'll not use STDERR_FILENO for logging ever, but rather open /dev/console */ | |
303 | void log_set_always_reopen_console(bool b); | |
304 | ||
305 | /* If turned on, we'll open the log stream implicitly if needed on each individual log call. This is normally not | |
306 | * desired as we want to reuse our logging streams. It is useful however */ | |
307 | void log_set_open_when_needed(bool b); | |
308 | ||
309 | /* 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 | |
310 | * stderr, the console or kmsg */ | |
311 | void log_set_prohibit_ipc(bool b); | |
312 | ||
313 | int log_dup_console(void); | |
314 | ||
315 | int log_syntax_internal( | |
316 | const char *unit, | |
317 | int level, | |
318 | const char *config_file, | |
319 | unsigned config_line, | |
320 | int error, | |
321 | const char *file, | |
322 | int line, | |
323 | const char *func, | |
324 | const char *format, ...) _printf_(9, 10); | |
325 | ||
326 | int log_syntax_invalid_utf8_internal( | |
327 | const char *unit, | |
328 | int level, | |
329 | const char *config_file, | |
330 | unsigned config_line, | |
331 | const char *file, | |
332 | int line, | |
333 | const char *func, | |
334 | const char *rvalue); | |
335 | ||
336 | int log_syntax_parse_error_internal( | |
337 | const char *unit, | |
338 | const char *config_file, | |
339 | unsigned config_line, | |
340 | int error, | |
341 | bool critical, /* When true, propagate the passed error, otherwise this always returns 0. */ | |
342 | const char *file, | |
343 | int line, | |
344 | const char *func, | |
345 | const char *lvalue, | |
346 | const char *rvalue); | |
347 | ||
348 | #define log_syntax(unit, level, config_file, config_line, error, ...) \ | |
349 | ({ \ | |
350 | int _level = (level), _e = (error); \ | |
351 | (log_get_max_level() >= LOG_PRI(_level)) \ | |
352 | ? log_syntax_internal(unit, _level, config_file, config_line, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ | |
353 | : -ERRNO_VALUE(_e); \ | |
354 | }) | |
355 | ||
356 | #define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ | |
357 | ({ \ | |
358 | int _level = (level); \ | |
359 | (log_get_max_level() >= LOG_PRI(_level)) \ | |
360 | ? log_syntax_invalid_utf8_internal(unit, _level, config_file, config_line, PROJECT_FILE, __LINE__, __func__, rvalue) \ | |
361 | : -EINVAL; \ | |
362 | }) | |
363 | ||
364 | #define log_syntax_parse_error_full(unit, config_file, config_line, error, critical, lvalue, rvalue) \ | |
365 | log_syntax_parse_error_internal(unit, config_file, config_line, error, critical, PROJECT_FILE, __LINE__, __func__, lvalue, rvalue) | |
366 | ||
367 | #define log_syntax_parse_error(unit, config_file, config_line, error, lvalue, rvalue) \ | |
368 | log_syntax_parse_error_full(unit, config_file, config_line, error, /* critical = */ false, lvalue, rvalue) | |
369 | ||
370 | #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG) | |
371 | ||
372 | void log_setup(void); | |
373 | ||
374 | const char* _log_set_prefix(const char *prefix, bool force); | |
375 | static inline const char* _log_unset_prefixp(const char **p) { | |
376 | assert(p); | |
377 | _log_set_prefix(*p, true); | |
378 | return NULL; | |
379 | } | |
380 | ||
381 | #define LOG_SET_PREFIX(prefix) \ | |
382 | _cleanup_(_log_unset_prefixp) _unused_ const char *CONCATENATE(_cleanup_log_unset_prefix_, UNIQ) = _log_set_prefix(prefix, false); |