]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/log.h
tree-wide: improve logging
[mirror_lxc.git] / src / lxc / log.h
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef __LXC_LOG_H
4 #define __LXC_LOG_H
5
6 #include <errno.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <sys/time.h>
10 #include <string.h>
11 #include <strings.h>
12 #include <stdbool.h>
13 #include <syslog.h>
14 #include <time.h>
15
16 #include "conf.h"
17
18 #ifndef O_CLOEXEC
19 #define O_CLOEXEC 02000000
20 #endif
21
22 #ifndef F_DUPFD_CLOEXEC
23 #define F_DUPFD_CLOEXEC 1030
24 #endif
25
26 #define LXC_LOG_PREFIX_SIZE 32
27 #define LXC_LOG_BUFFER_SIZE 4096
28
29 /* predefined lxc log priorities. */
30 enum lxc_loglevel {
31 LXC_LOG_LEVEL_TRACE,
32 LXC_LOG_LEVEL_DEBUG,
33 LXC_LOG_LEVEL_INFO,
34 LXC_LOG_LEVEL_NOTICE,
35 LXC_LOG_LEVEL_WARN,
36 LXC_LOG_LEVEL_ERROR,
37 LXC_LOG_LEVEL_CRIT,
38 LXC_LOG_LEVEL_ALERT,
39 LXC_LOG_LEVEL_FATAL,
40 LXC_LOG_LEVEL_NOTSET,
41 };
42
43 /* location information of the logging event */
44 struct lxc_log_locinfo {
45 const char *file;
46 const char *func;
47 int line;
48 };
49
50 #define LXC_LOG_LOCINFO_INIT \
51 { .file = __FILE__, .func = __func__, .line = __LINE__ }
52
53 /* brief logging event object */
54 struct lxc_log_event {
55 const char *category;
56 int priority;
57 struct timespec timestamp;
58 struct lxc_log_locinfo *locinfo;
59 const char *fmt;
60 va_list *vap;
61 };
62
63 /* log appender object */
64 struct lxc_log_appender {
65 const char *name;
66 int (*append)(const struct lxc_log_appender *, struct lxc_log_event *);
67
68 /*
69 * appenders can be stacked
70 */
71 struct lxc_log_appender *next;
72 };
73
74 /* log category object */
75 struct lxc_log_category {
76 const char *name;
77 int priority;
78 struct lxc_log_appender *appender;
79 const struct lxc_log_category *parent;
80 };
81
82 #ifndef NO_LXC_CONF
83 extern int lxc_log_use_global_fd;
84 #endif
85
86 /*
87 * Returns true if the chained priority is equal to or higher than
88 * given priority.
89 */
90 static inline int lxc_log_priority_is_enabled(const struct lxc_log_category *category,
91 int priority)
92 {
93 while (category->priority == LXC_LOG_LEVEL_NOTSET && category->parent)
94 category = category->parent;
95
96 int cmp_prio = category->priority;
97 #ifndef NO_LXC_CONF
98 if (!lxc_log_use_global_fd && current_config &&
99 current_config->loglevel != LXC_LOG_LEVEL_NOTSET)
100 cmp_prio = current_config->loglevel;
101 #endif
102
103 return priority >= cmp_prio;
104 }
105
106 /*
107 * converts a priority to a literal string
108 */
109 static inline const char *lxc_log_priority_to_string(int priority)
110 {
111 switch (priority) {
112 case LXC_LOG_LEVEL_TRACE:
113 return "TRACE";
114 case LXC_LOG_LEVEL_DEBUG:
115 return "DEBUG";
116 case LXC_LOG_LEVEL_INFO:
117 return "INFO";
118 case LXC_LOG_LEVEL_NOTICE:
119 return "NOTICE";
120 case LXC_LOG_LEVEL_WARN:
121 return "WARN";
122 case LXC_LOG_LEVEL_ERROR:
123 return "ERROR";
124 case LXC_LOG_LEVEL_CRIT:
125 return "CRIT";
126 case LXC_LOG_LEVEL_ALERT:
127 return "ALERT";
128 case LXC_LOG_LEVEL_FATAL:
129 return "FATAL";
130 }
131
132 return "NOTSET";
133 }
134
135 static inline const char *lxc_syslog_priority_to_string(int priority)
136 {
137 switch (priority) {
138 case LOG_DAEMON:
139 return "daemon";
140 case LOG_LOCAL0:
141 return "local0";
142 case LOG_LOCAL1:
143 return "local1";
144 case LOG_LOCAL2:
145 return "local2";
146 case LOG_LOCAL3:
147 return "local3";
148 case LOG_LOCAL4:
149 return "local4";
150 case LOG_LOCAL5:
151 return "local5";
152 case LOG_LOCAL6:
153 return "local6";
154 case LOG_LOCAL7:
155 return "local7";
156 }
157
158 return "NOTSET";
159 }
160
161 /*
162 * converts a literal priority to an int
163 */
164 static inline int lxc_log_priority_to_int(const char *name)
165 {
166 if (strcasecmp("TRACE", name) == 0)
167 return LXC_LOG_LEVEL_TRACE;
168 if (strcasecmp("DEBUG", name) == 0)
169 return LXC_LOG_LEVEL_DEBUG;
170 if (strcasecmp("INFO", name) == 0)
171 return LXC_LOG_LEVEL_INFO;
172 if (strcasecmp("NOTICE", name) == 0)
173 return LXC_LOG_LEVEL_NOTICE;
174 if (strcasecmp("WARN", name) == 0)
175 return LXC_LOG_LEVEL_WARN;
176 if (strcasecmp("ERROR", name) == 0)
177 return LXC_LOG_LEVEL_ERROR;
178 if (strcasecmp("CRIT", name) == 0)
179 return LXC_LOG_LEVEL_CRIT;
180 if (strcasecmp("ALERT", name) == 0)
181 return LXC_LOG_LEVEL_ALERT;
182 if (strcasecmp("FATAL", name) == 0)
183 return LXC_LOG_LEVEL_FATAL;
184
185 return LXC_LOG_LEVEL_NOTSET;
186 }
187
188 static inline int lxc_syslog_priority_to_int(const char *name)
189 {
190 if (strcasecmp("daemon", name) == 0)
191 return LOG_DAEMON;
192 if (strcasecmp("local0", name) == 0)
193 return LOG_LOCAL0;
194 if (strcasecmp("local1", name) == 0)
195 return LOG_LOCAL1;
196 if (strcasecmp("local2", name) == 0)
197 return LOG_LOCAL2;
198 if (strcasecmp("local3", name) == 0)
199 return LOG_LOCAL3;
200 if (strcasecmp("local4", name) == 0)
201 return LOG_LOCAL4;
202 if (strcasecmp("local5", name) == 0)
203 return LOG_LOCAL5;
204 if (strcasecmp("local6", name) == 0)
205 return LOG_LOCAL6;
206 if (strcasecmp("local7", name) == 0)
207 return LOG_LOCAL7;
208
209 return -EINVAL;
210 }
211
212 static inline void __lxc_log_append(const struct lxc_log_appender *appender,
213 struct lxc_log_event *event)
214 {
215 va_list va;
216 va_list *va_keep = event->vap;
217
218 while (appender) {
219 va_copy(va, *va_keep);
220 event->vap = &va;
221 appender->append(appender, event);
222 appender = appender->next;
223 va_end(va);
224 }
225 }
226
227 static inline void __lxc_log(const struct lxc_log_category *category,
228 struct lxc_log_event *event)
229 {
230 while (category) {
231 __lxc_log_append(category->appender, event);
232 category = category->parent;
233 }
234 }
235
236 /*
237 * Helper macro to define log functions.
238 */
239 #define lxc_log_priority_define(acategory, LEVEL) \
240 \
241 __lxc_unused __attribute__ ((format (printf, 2, 3))) \
242 static inline void LXC_##LEVEL(struct lxc_log_locinfo *, const char *, ...); \
243 \
244 __lxc_unused static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
245 const char* format, ...) \
246 { \
247 if (lxc_log_priority_is_enabled(acategory, LXC_LOG_LEVEL_##LEVEL)) { \
248 va_list va_ref; \
249 int saved_errno; \
250 struct lxc_log_event evt = { \
251 .category = (acategory)->name, \
252 .priority = LXC_LOG_LEVEL_##LEVEL, \
253 .fmt = format, \
254 .locinfo = locinfo \
255 }; \
256 \
257 /* clock_gettime() is explicitly marked as MT-Safe \
258 * without restrictions. So let's use it for our \
259 * logging stamps. \
260 */ \
261 saved_errno = errno; \
262 (void)clock_gettime(CLOCK_REALTIME, &evt.timestamp); \
263 \
264 va_start(va_ref, format); \
265 evt.vap = &va_ref; \
266 __lxc_log(acategory, &evt); \
267 va_end(va_ref); \
268 errno = saved_errno; \
269 } \
270 }
271
272 /*
273 * Helper macro to define and use static categories.
274 */
275 #define lxc_log_category_define(name, parent) \
276 extern struct lxc_log_category lxc_log_category_##parent; \
277 struct lxc_log_category lxc_log_category_##name = { \
278 #name, \
279 LXC_LOG_LEVEL_NOTSET, \
280 NULL, \
281 &lxc_log_category_##parent \
282 };
283
284 #define lxc_log_define(name, parent) \
285 lxc_log_category_define(name, parent) \
286 \
287 lxc_log_priority_define(&lxc_log_category_##name, TRACE) \
288 lxc_log_priority_define(&lxc_log_category_##name, DEBUG) \
289 lxc_log_priority_define(&lxc_log_category_##name, INFO) \
290 lxc_log_priority_define(&lxc_log_category_##name, NOTICE) \
291 lxc_log_priority_define(&lxc_log_category_##name, WARN) \
292 lxc_log_priority_define(&lxc_log_category_##name, ERROR) \
293 lxc_log_priority_define(&lxc_log_category_##name, CRIT) \
294 lxc_log_priority_define(&lxc_log_category_##name, ALERT) \
295 lxc_log_priority_define(&lxc_log_category_##name, FATAL)
296
297 #define lxc_log_category_priority(name) \
298 (lxc_log_priority_to_string(lxc_log_category_##name.priority))
299
300 /*
301 * Helper macro to define errno string.
302 */
303 #if HAVE_STRERROR_R
304 #ifndef HAVE_DECL_STRERROR_R
305 #ifdef STRERROR_R_CHAR_P
306 char *strerror_r(int errnum, char *buf, size_t buflen);
307 #else
308 int strerror_r(int errnum, char *buf, size_t buflen);
309 #endif
310 #endif
311
312 #ifdef STRERROR_R_CHAR_P
313 #define lxc_log_strerror_r \
314 char errno_buf[PATH_MAX / 2] = {"Failed to get errno string"}; \
315 char *ptr = NULL; \
316 { \
317 int __saved_errno = errno; \
318 ptr = strerror_r(errno, errno_buf, sizeof(errno_buf)); \
319 errno = __saved_errno; \
320 if (!ptr) \
321 ptr = errno_buf; \
322 }
323 #else
324 #define lxc_log_strerror_r \
325 char errno_buf[PATH_MAX / 2] = {"Failed to get errno string"}; \
326 char *ptr = errno_buf; \
327 { \
328 int __saved_errno = errno; \
329 (void)strerror_r(errno, errno_buf, sizeof(errno_buf)); \
330 errno = __saved_errno; \
331 }
332 #endif
333 #elif ENFORCE_THREAD_SAFETY
334 #error ENFORCE_THREAD_SAFETY was set but cannot be guaranteed
335 #else
336 #define lxc_log_strerror_r \
337 char *ptr = NULL; \
338 { \
339 ptr = strerror(errno); \
340 }
341 #endif
342
343 /*
344 * top categories
345 */
346 #define TRACE(format, ...) do { \
347 struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
348 LXC_TRACE(&locinfo, format, ##__VA_ARGS__); \
349 } while (0)
350
351 #define DEBUG(format, ...) do { \
352 struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
353 LXC_DEBUG(&locinfo, format, ##__VA_ARGS__); \
354 } while (0)
355
356 #define INFO(format, ...) do { \
357 struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
358 LXC_INFO(&locinfo, format, ##__VA_ARGS__); \
359 } while (0)
360
361 #define NOTICE(format, ...) do { \
362 struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
363 LXC_NOTICE(&locinfo, format, ##__VA_ARGS__); \
364 } while (0)
365
366 #define WARN(format, ...) do { \
367 struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
368 LXC_WARN(&locinfo, format, ##__VA_ARGS__); \
369 } while (0)
370
371 #define ERROR(format, ...) do { \
372 struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
373 LXC_ERROR(&locinfo, format, ##__VA_ARGS__); \
374 } while (0)
375
376 #define CRIT(format, ...) do { \
377 struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
378 LXC_CRIT(&locinfo, format, ##__VA_ARGS__); \
379 } while (0)
380
381 #define ALERT(format, ...) do { \
382 struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
383 LXC_ALERT(&locinfo, format, ##__VA_ARGS__); \
384 } while (0)
385
386 #define FATAL(format, ...) do { \
387 struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
388 LXC_FATAL(&locinfo, format, ##__VA_ARGS__); \
389 } while (0)
390
391 #if HAVE_M_FORMAT
392 #define SYSTRACE(format, ...) \
393 TRACE("%m - " format, ##__VA_ARGS__)
394 #else
395 #define SYSTRACE(format, ...) \
396 do { \
397 lxc_log_strerror_r; \
398 TRACE("%s - " format, ptr, ##__VA_ARGS__); \
399 } while (0)
400 #endif
401
402 #if HAVE_M_FORMAT
403 #define SYSDEBUG(format, ...) \
404 DEBUG("%m - " format, ##__VA_ARGS__)
405 #else
406 #define SYSDEBUG(format, ...) \
407 do { \
408 lxc_log_strerror_r; \
409 DEBUG("%s - " format, ptr, ##__VA_ARGS__); \
410 } while (0)
411 #endif
412
413
414 #if HAVE_M_FORMAT
415 #define SYSINFO(format, ...) \
416 INFO("%m - " format, ##__VA_ARGS__)
417 #else
418 #define SYSINFO(format, ...) \
419 do { \
420 lxc_log_strerror_r; \
421 INFO("%s - " format, ptr, ##__VA_ARGS__); \
422 } while (0)
423 #endif
424
425 #if HAVE_M_FORMAT
426 #define SYSNOTICE(format, ...) \
427 NOTICE("%m - " format, ##__VA_ARGS__)
428 #else
429 #define SYSNOTICE(format, ...) \
430 do { \
431 lxc_log_strerror_r; \
432 NOTICE("%s - " format, ptr, ##__VA_ARGS__); \
433 } while (0)
434 #endif
435
436 #if HAVE_M_FORMAT
437 #define SYSWARN(format, ...) \
438 WARN("%m - " format, ##__VA_ARGS__)
439 #else
440 #define SYSWARN(format, ...) \
441 do { \
442 lxc_log_strerror_r; \
443 WARN("%s - " format, ptr, ##__VA_ARGS__); \
444 } while (0)
445 #endif
446
447 #if HAVE_M_FORMAT
448 #define SYSERROR(format, ...) \
449 ERROR("%m - " format, ##__VA_ARGS__)
450 #else
451 #define SYSERROR(format, ...) \
452 do { \
453 lxc_log_strerror_r; \
454 ERROR("%s - " format, ptr, ##__VA_ARGS__); \
455 } while (0)
456 #endif
457
458 #if HAVE_M_FORMAT
459 #define CMD_SYSERROR(format, ...) \
460 fprintf(stderr, "%m - " format, ##__VA_ARGS__)
461 #else
462 #define CMD_SYSERROR(format, ...) \
463 do { \
464 lxc_log_strerror_r; \
465 fprintf(stderr, "%s - " format, ptr, ##__VA_ARGS__); \
466 } while (0)
467 #endif
468
469 #if HAVE_M_FORMAT
470 #define CMD_SYSINFO(format, ...) \
471 printf("%m - " format, ##__VA_ARGS__)
472 #else
473 #define CMD_SYSINFO(format, ...) \
474 do { \
475 lxc_log_strerror_r; \
476 printf("%s - " format, ptr, ##__VA_ARGS__); \
477 } while (0)
478 #endif
479
480 #define log_error_errno(__ret__, __errno__, format, ...) \
481 ({ \
482 errno = __errno__; \
483 SYSERROR(format, ##__VA_ARGS__); \
484 __ret__; \
485 })
486
487 #define log_error(__ret__, format, ...) \
488 ({ \
489 ERROR(format, ##__VA_ARGS__); \
490 __ret__; \
491 })
492
493 #define log_trace_errno(__ret__, __errno__, format, ...) \
494 ({ \
495 errno = __errno__; \
496 SYSTRACE(format, ##__VA_ARGS__); \
497 __ret__; \
498 })
499
500 #define log_trace(__ret__, format, ...) \
501 ({ \
502 TRACE(format, ##__VA_ARGS__); \
503 __ret__; \
504 })
505
506 #define log_warn_errno(__ret__, __errno__, format, ...) \
507 ({ \
508 errno = __errno__; \
509 SYSWARN(format, ##__VA_ARGS__); \
510 __ret__; \
511 })
512
513 #define log_warn(__ret__, format, ...) \
514 ({ \
515 WARN(format, ##__VA_ARGS__); \
516 __ret__; \
517 })
518
519 #define log_debug_errno(__ret__, __errno__, format, ...) \
520 ({ \
521 errno = __errno__; \
522 SYSDEBUG(format, ##__VA_ARGS__); \
523 __ret__; \
524 })
525
526 #define log_debug(__ret__, format, ...) \
527 ({ \
528 DEBUG(format, ##__VA_ARGS__); \
529 __ret__; \
530 })
531
532 #define log_info_errno(__ret__, __errno__, format, ...) \
533 ({ \
534 errno = __errno__; \
535 SYSINFO(format, ##__VA_ARGS__); \
536 __ret__; \
537 })
538
539 #define log_info(__ret__, format, ...) \
540 ({ \
541 INFO(format, ##__VA_ARGS__); \
542 __ret__; \
543 })
544
545 extern int lxc_log_fd;
546
547 extern int lxc_log_syslog(int facility);
548 extern void lxc_log_enable_syslog(void);
549 extern int lxc_log_set_level(int *dest, int level);
550 extern int lxc_log_get_level(void);
551 extern bool lxc_log_has_valid_level(void);
552 extern int lxc_log_set_file(int *fd, const char *fname);
553 extern const char *lxc_log_get_file(void);
554 extern void lxc_log_set_prefix(const char *prefix);
555 extern const char *lxc_log_get_prefix(void);
556 extern void lxc_log_options_no_override(void);
557 #endif