]>
| 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 "basic-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 | # define ASSERT_UNDERFLOW(x) assert((x) >= INT_MIN) | |
| 196 | #else | |
| 197 | # define ASSERT_NON_ZERO(x) | |
| 198 | # define ASSERT_UNDERFLOW(x) | |
| 199 | #endif | |
| 200 | ||
| 201 | /* We often call log macros with ssize_t instead of int, so check for underflows, | |
| 202 | * as ssize_t is not guaranteed to be the same as int, and we usually do | |
| 203 | * 'return log_errno...' from functions that return 'int' */ | |
| 204 | #define log_full_errno(level, error, ...) \ | |
| 205 | ({ \ | |
| 206 | int64_t _error = (error); \ | |
| 207 | ASSERT_UNDERFLOW(_error); \ | |
| 208 | ASSERT_NON_ZERO(_error); \ | |
| 209 | log_full_errno_zerook(level, (int)_error, __VA_ARGS__); \ | |
| 210 | }) | |
| 211 | ||
| 212 | #define log_full(level, fmt, ...) \ | |
| 213 | ({ \ | |
| 214 | if (BUILD_MODE_DEVELOPER) \ | |
| 215 | assert(!strstr(fmt, "%m")); \ | |
| 216 | (void) log_full_errno_zerook(level, 0, fmt, ##__VA_ARGS__); \ | |
| 217 | }) | |
| 218 | ||
| 219 | int log_emergency_level(void); | |
| 220 | ||
| 221 | /* Normal logging */ | |
| 222 | #define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) | |
| 223 | #define log_info(...) log_full(LOG_INFO, __VA_ARGS__) | |
| 224 | #define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) | |
| 225 | #define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) | |
| 226 | #define log_error(...) log_full(LOG_ERR, __VA_ARGS__) | |
| 227 | #define log_emergency(...) log_full(log_emergency_level(), __VA_ARGS__) | |
| 228 | ||
| 229 | /* Logging triggered by an errno-like error */ | |
| 230 | #define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__) | |
| 231 | #define log_info_errno(error, ...) log_full_errno(LOG_INFO, error, __VA_ARGS__) | |
| 232 | #define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__) | |
| 233 | #define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__) | |
| 234 | #define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__) | |
| 235 | #define log_emergency_errno(error, ...) log_full_errno(log_emergency_level(), error, __VA_ARGS__) | |
| 236 | ||
| 237 | /* This logs at the specified level the first time it is called, and then | |
| 238 | * logs at debug. If the specified level is debug, this logs only the first | |
| 239 | * time it is called. */ | |
| 240 | #define log_once(level, ...) \ | |
| 241 | ({ \ | |
| 242 | if (ONCE) \ | |
| 243 | log_full(level, __VA_ARGS__); \ | |
| 244 | else if (LOG_PRI(level) != LOG_DEBUG) \ | |
| 245 | log_debug(__VA_ARGS__); \ | |
| 246 | }) | |
| 247 | ||
| 248 | #define log_once_errno(level, error, ...) \ | |
| 249 | ({ \ | |
| 250 | int _err = (error); \ | |
| 251 | if (ONCE) \ | |
| 252 | _err = log_full_errno(level, _err, __VA_ARGS__); \ | |
| 253 | else if (LOG_PRI(level) != LOG_DEBUG) \ | |
| 254 | _err = log_debug_errno(_err, __VA_ARGS__); \ | |
| 255 | else \ | |
| 256 | _err = -ERRNO_VALUE(_err); \ | |
| 257 | _err; \ | |
| 258 | }) | |
| 259 | ||
| 260 | #if LOG_TRACE | |
| 261 | # define log_trace(...) log_debug(__VA_ARGS__) | |
| 262 | # define log_trace_errno(...) log_debug_errno(__VA_ARGS__) | |
| 263 | #else | |
| 264 | # define log_trace(...) do {} while (0) | |
| 265 | # define log_trace_errno(e, ...) (-ERRNO_VALUE(e)) | |
| 266 | #endif | |
| 267 | ||
| 268 | /* Structured logging */ | |
| 269 | #define log_struct_errno(level, error, ...) \ | |
| 270 | log_struct_internal(level, error, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__, NULL) | |
| 271 | #define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__) | |
| 272 | ||
| 273 | #define log_struct_iovec_errno(level, error, iovec, n_iovec) \ | |
| 274 | log_struct_iovec_internal(level, error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec) | |
| 275 | #define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec) | |
| 276 | ||
| 277 | /* This modifies the buffer passed! */ | |
| 278 | #define log_dump(level, buffer) \ | |
| 279 | log_dump_internal(level, 0, PROJECT_FILE, __LINE__, __func__, buffer) | |
| 280 | ||
| 281 | #define log_oom_full(level) log_oom_internal(level, PROJECT_FILE, __LINE__, __func__) | |
| 282 | #define log_oom() log_oom_full(LOG_ERR) | |
| 283 | #define log_oom_debug() log_oom_full(LOG_DEBUG) | |
| 284 | #define log_oom_warning() log_oom_full(LOG_WARNING) | |
| 285 | ||
| 286 | bool log_on_console(void) _pure_; | |
| 287 | ||
| 288 | /* Helper to wrap the main message in structured logging. The macro doesn't do much, | |
| 289 | * except to provide visual grouping of the format string and its arguments. */ | |
| 290 | #if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__) | |
| 291 | /* Do a fake formatting of the message string to let the scanner verify the arguments against the format | |
| 292 | * message. The variable will never be set to true, but we don't tell the compiler that :) */ | |
| 293 | extern bool _log_message_dummy; | |
| 294 | # define LOG_ITEM(fmt, ...) "%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__ | |
| 295 | # define LOG_MESSAGE(fmt, ...) LOG_ITEM("MESSAGE=" fmt, ##__VA_ARGS__) | |
| 296 | #else | |
| 297 | # define LOG_ITEM(fmt, ...) fmt, ##__VA_ARGS__ | |
| 298 | # define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ | |
| 299 | #endif | |
| 300 | ||
| 301 | #define LOG_MESSAGE_ID(id) LOG_ITEM("MESSAGE_ID=" id) | |
| 302 | ||
| 303 | void log_received_signal(int level, const struct signalfd_siginfo *si); | |
| 304 | ||
| 305 | /* If turned on, any requests for a log target involving "syslog" will be implicitly upgraded to the equivalent journal target */ | |
| 306 | void log_set_upgrade_syslog_to_journal(bool b); | |
| 307 | ||
| 308 | /* If turned on, and log_open() is called, we'll not use STDERR_FILENO for logging ever, but rather open /dev/console */ | |
| 309 | void log_set_always_reopen_console(bool b); | |
| 310 | ||
| 311 | /* If turned on, we'll open the log stream implicitly if needed on each individual log call. This is normally not | |
| 312 | * desired as we want to reuse our logging streams. It is useful however */ | |
| 313 | void log_set_open_when_needed(bool b); | |
| 314 | ||
| 315 | /* 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 | |
| 316 | * stderr, the console or kmsg */ | |
| 317 | void log_set_prohibit_ipc(bool b); | |
| 318 | ||
| 319 | int log_dup_console(void); | |
| 320 | ||
| 321 | int log_syntax_internal( | |
| 322 | const char *unit, | |
| 323 | int level, | |
| 324 | const char *config_file, | |
| 325 | unsigned config_line, | |
| 326 | int error, | |
| 327 | const char *file, | |
| 328 | int line, | |
| 329 | const char *func, | |
| 330 | const char *format, ...) _printf_(9, 10); | |
| 331 | ||
| 332 | int log_syntax_invalid_utf8_internal( | |
| 333 | const char *unit, | |
| 334 | int level, | |
| 335 | const char *config_file, | |
| 336 | unsigned config_line, | |
| 337 | const char *file, | |
| 338 | int line, | |
| 339 | const char *func, | |
| 340 | const char *rvalue); | |
| 341 | ||
| 342 | int log_syntax_parse_error_internal( | |
| 343 | const char *unit, | |
| 344 | const char *config_file, | |
| 345 | unsigned config_line, | |
| 346 | int error, | |
| 347 | bool critical, /* When true, propagate the passed error, otherwise this always returns 0. */ | |
| 348 | const char *file, | |
| 349 | int line, | |
| 350 | const char *func, | |
| 351 | const char *lvalue, | |
| 352 | const char *rvalue); | |
| 353 | ||
| 354 | #define log_syntax(unit, level, config_file, config_line, error, ...) \ | |
| 355 | ({ \ | |
| 356 | int _level = (level), _e = (error); \ | |
| 357 | (log_get_max_level() >= LOG_PRI(_level)) \ | |
| 358 | ? log_syntax_internal(unit, _level, config_file, config_line, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ | |
| 359 | : -ERRNO_VALUE(_e); \ | |
| 360 | }) | |
| 361 | ||
| 362 | #define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ | |
| 363 | ({ \ | |
| 364 | int _level = (level); \ | |
| 365 | (log_get_max_level() >= LOG_PRI(_level)) \ | |
| 366 | ? log_syntax_invalid_utf8_internal(unit, _level, config_file, config_line, PROJECT_FILE, __LINE__, __func__, rvalue) \ | |
| 367 | : -EINVAL; \ | |
| 368 | }) | |
| 369 | ||
| 370 | #define log_syntax_parse_error_full(unit, config_file, config_line, error, critical, lvalue, rvalue) \ | |
| 371 | log_syntax_parse_error_internal(unit, config_file, config_line, error, critical, PROJECT_FILE, __LINE__, __func__, lvalue, rvalue) | |
| 372 | ||
| 373 | #define log_syntax_parse_error(unit, config_file, config_line, error, lvalue, rvalue) \ | |
| 374 | log_syntax_parse_error_full(unit, config_file, config_line, error, /* critical = */ false, lvalue, rvalue) | |
| 375 | ||
| 376 | #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG) | |
| 377 | ||
| 378 | void log_setup(void); | |
| 379 | ||
| 380 | const char* _log_set_prefix(const char *prefix, bool force); | |
| 381 | static inline const char* _log_unset_prefixp(const char **p) { | |
| 382 | assert(p); | |
| 383 | _log_set_prefix(*p, true); | |
| 384 | return NULL; | |
| 385 | } | |
| 386 | ||
| 387 | #define LOG_SET_PREFIX(prefix) \ | |
| 388 | _cleanup_(_log_unset_prefixp) _unused_ const char *CONCATENATE(_cleanup_log_unset_prefix_, UNIQ) = _log_set_prefix(prefix, false); |