]>
Commit | Line | Data |
---|---|---|
e0b4037d DL |
1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
9afe19d6 | 7 | * Daniel Lezcano <daniel.lezcano at free.fr> |
e0b4037d DL |
8 | * Cedric Le Goater <legoater@free.fr> |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
250b1eec | 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
e0b4037d | 23 | */ |
f1a4a029 ÇO |
24 | #ifndef __LXC_LOG_H |
25 | #define __LXC_LOG_H | |
0ad19a3f | 26 | |
9f4f402a ÇO |
27 | #include "config.h" |
28 | ||
76d0127f | 29 | #include <errno.h> |
cb8c5720 CLG |
30 | #include <stdarg.h> |
31 | #include <stdio.h> | |
32 | #include <sys/time.h> | |
33 | #include <string.h> | |
65441ac9 | 34 | #include <strings.h> |
fabf7361 | 35 | #include <stdbool.h> |
76d0127f | 36 | #include <syslog.h> |
c57dbb96 | 37 | #include <time.h> |
cb8c5720 | 38 | |
858377e4 SH |
39 | #include "conf.h" |
40 | ||
eabbb2f0 MN |
41 | #ifndef O_CLOEXEC |
42 | #define O_CLOEXEC 02000000 | |
43 | #endif | |
44 | ||
45 | #ifndef F_DUPFD_CLOEXEC | |
46 | #define F_DUPFD_CLOEXEC 1030 | |
47 | #endif | |
48 | ||
49 | #define LXC_LOG_PREFIX_SIZE 32 | |
ed408e66 | 50 | #define LXC_LOG_BUFFER_SIZE 4096 |
eabbb2f0 | 51 | |
13aad0ae SG |
52 | /* This attribute is required to silence clang warnings */ |
53 | #if defined(__GNUC__) | |
54 | #define ATTR_UNUSED __attribute__ ((unused)) | |
55 | #else | |
56 | #define ATTR_UNUSED | |
57 | #endif | |
58 | ||
76d0127f | 59 | /* predefined lxc log priorities. */ |
4a85ce2a | 60 | enum lxc_loglevel { |
4b73005c CB |
61 | LXC_LOG_LEVEL_TRACE, |
62 | LXC_LOG_LEVEL_DEBUG, | |
63 | LXC_LOG_LEVEL_INFO, | |
64 | LXC_LOG_LEVEL_NOTICE, | |
65 | LXC_LOG_LEVEL_WARN, | |
66 | LXC_LOG_LEVEL_ERROR, | |
67 | LXC_LOG_LEVEL_CRIT, | |
68 | LXC_LOG_LEVEL_ALERT, | |
69 | LXC_LOG_LEVEL_FATAL, | |
70 | LXC_LOG_LEVEL_NOTSET, | |
cb8c5720 CLG |
71 | }; |
72 | ||
73 | /* location information of the logging event */ | |
74 | struct lxc_log_locinfo { | |
75 | const char *file; | |
76 | const char *func; | |
77 | int line; | |
78 | }; | |
79 | ||
80 | #define LXC_LOG_LOCINFO_INIT \ | |
81 | { .file = __FILE__, .func = __func__, .line = __LINE__ } | |
82 | ||
83 | /* brief logging event object */ | |
84 | struct lxc_log_event { | |
85 | const char* category; | |
86 | int priority; | |
c57dbb96 | 87 | struct timespec timestamp; |
cb8c5720 CLG |
88 | struct lxc_log_locinfo *locinfo; |
89 | const char *fmt; | |
5fd8380b | 90 | va_list *vap; |
cb8c5720 CLG |
91 | }; |
92 | ||
93 | /* log appender object */ | |
94 | struct lxc_log_appender { | |
95 | const char* name; | |
5fd8380b | 96 | int (*append)(const struct lxc_log_appender *, struct lxc_log_event *); |
cb8c5720 CLG |
97 | |
98 | /* | |
99 | * appenders can be stacked | |
100 | */ | |
101 | struct lxc_log_appender *next; | |
102 | }; | |
103 | ||
104 | /* log category object */ | |
105 | struct lxc_log_category { | |
106 | const char *name; | |
107 | int priority; | |
108 | struct lxc_log_appender *appender; | |
109 | const struct lxc_log_category *parent; | |
110 | }; | |
111 | ||
858377e4 SH |
112 | #ifndef NO_LXC_CONF |
113 | extern int lxc_log_use_global_fd; | |
114 | #endif | |
115 | ||
cb8c5720 CLG |
116 | /* |
117 | * Returns true if the chained priority is equal to or higher than | |
118 | * given priority. | |
119 | */ | |
120 | static inline int | |
121 | lxc_log_priority_is_enabled(const struct lxc_log_category* category, | |
122 | int priority) | |
123 | { | |
4b73005c | 124 | while (category->priority == LXC_LOG_LEVEL_NOTSET && |
cb8c5720 CLG |
125 | category->parent) |
126 | category = category->parent; | |
127 | ||
858377e4 SH |
128 | int cmp_prio = category->priority; |
129 | #ifndef NO_LXC_CONF | |
130 | if (!lxc_log_use_global_fd && current_config && | |
4b73005c | 131 | current_config->loglevel != LXC_LOG_LEVEL_NOTSET) |
858377e4 SH |
132 | cmp_prio = current_config->loglevel; |
133 | #endif | |
134 | ||
135 | return priority >= cmp_prio; | |
cb8c5720 CLG |
136 | } |
137 | ||
138 | /* | |
139 | * converts a priority to a literal string | |
140 | */ | |
141 | static inline const char* lxc_log_priority_to_string(int priority) | |
142 | { | |
143 | switch (priority) { | |
4b73005c CB |
144 | case LXC_LOG_LEVEL_TRACE: return "TRACE"; |
145 | case LXC_LOG_LEVEL_DEBUG: return "DEBUG"; | |
146 | case LXC_LOG_LEVEL_INFO: return "INFO"; | |
147 | case LXC_LOG_LEVEL_NOTICE: return "NOTICE"; | |
148 | case LXC_LOG_LEVEL_WARN: return "WARN"; | |
149 | case LXC_LOG_LEVEL_ERROR: return "ERROR"; | |
150 | case LXC_LOG_LEVEL_CRIT: return "CRIT"; | |
151 | case LXC_LOG_LEVEL_ALERT: return "ALERT"; | |
152 | case LXC_LOG_LEVEL_FATAL: return "FATAL"; | |
cb8c5720 CLG |
153 | default: |
154 | return "NOTSET"; | |
155 | } | |
156 | } | |
76d0127f CB |
157 | |
158 | static inline const char* lxc_syslog_priority_to_string(int priority) | |
159 | { | |
160 | switch (priority) { | |
161 | case LOG_DAEMON: return "daemon"; | |
162 | case LOG_LOCAL0: return "local0"; | |
163 | case LOG_LOCAL1: return "local1"; | |
164 | case LOG_LOCAL2: return "local2"; | |
165 | case LOG_LOCAL3: return "local3"; | |
166 | case LOG_LOCAL4: return "local4"; | |
167 | case LOG_LOCAL5: return "local5"; | |
168 | case LOG_LOCAL6: return "local6"; | |
169 | case LOG_LOCAL7: return "local7"; | |
170 | default: | |
171 | return "NOTSET"; | |
172 | } | |
173 | } | |
174 | ||
cb8c5720 CLG |
175 | /* |
176 | * converts a literal priority to an int | |
177 | */ | |
178 | static inline int lxc_log_priority_to_int(const char* name) | |
179 | { | |
4b73005c CB |
180 | if (!strcasecmp("TRACE", name)) return LXC_LOG_LEVEL_TRACE; |
181 | if (!strcasecmp("DEBUG", name)) return LXC_LOG_LEVEL_DEBUG; | |
182 | if (!strcasecmp("INFO", name)) return LXC_LOG_LEVEL_INFO; | |
183 | if (!strcasecmp("NOTICE", name)) return LXC_LOG_LEVEL_NOTICE; | |
184 | if (!strcasecmp("WARN", name)) return LXC_LOG_LEVEL_WARN; | |
185 | if (!strcasecmp("ERROR", name)) return LXC_LOG_LEVEL_ERROR; | |
186 | if (!strcasecmp("CRIT", name)) return LXC_LOG_LEVEL_CRIT; | |
187 | if (!strcasecmp("ALERT", name)) return LXC_LOG_LEVEL_ALERT; | |
188 | if (!strcasecmp("FATAL", name)) return LXC_LOG_LEVEL_FATAL; | |
189 | ||
190 | return LXC_LOG_LEVEL_NOTSET; | |
cb8c5720 CLG |
191 | } |
192 | ||
76d0127f CB |
193 | static inline int lxc_syslog_priority_to_int(const char* name) |
194 | { | |
195 | if (!strcasecmp("daemon", name)) return LOG_DAEMON; | |
196 | if (!strcasecmp("local0", name)) return LOG_LOCAL0; | |
197 | if (!strcasecmp("local1", name)) return LOG_LOCAL1; | |
198 | if (!strcasecmp("local2", name)) return LOG_LOCAL2; | |
199 | if (!strcasecmp("local3", name)) return LOG_LOCAL3; | |
200 | if (!strcasecmp("local4", name)) return LOG_LOCAL4; | |
201 | if (!strcasecmp("local5", name)) return LOG_LOCAL5; | |
202 | if (!strcasecmp("local6", name)) return LOG_LOCAL6; | |
203 | if (!strcasecmp("local7", name)) return LOG_LOCAL7; | |
204 | ||
205 | return -EINVAL; | |
206 | } | |
207 | ||
cb8c5720 CLG |
208 | static inline void |
209 | __lxc_log_append(const struct lxc_log_appender *appender, | |
5fd8380b | 210 | struct lxc_log_event* event) |
cb8c5720 | 211 | { |
5fd8380b MN |
212 | va_list va, *va_keep; |
213 | va_keep = event->vap; | |
214 | ||
cb8c5720 | 215 | while (appender) { |
5fd8380b MN |
216 | va_copy(va, *va_keep); |
217 | event->vap = &va; | |
cb8c5720 CLG |
218 | appender->append(appender, event); |
219 | appender = appender->next; | |
5fd8380b | 220 | va_end(va); |
cb8c5720 CLG |
221 | } |
222 | } | |
223 | ||
224 | static inline void | |
225 | __lxc_log(const struct lxc_log_category* category, | |
5fd8380b | 226 | struct lxc_log_event* event) |
cb8c5720 CLG |
227 | { |
228 | while (category) { | |
229 | __lxc_log_append(category->appender, event); | |
230 | category = category->parent; | |
231 | } | |
232 | } | |
233 | ||
234 | /* | |
e6a19d26 | 235 | * Helper macro to define log functions. |
cb8c5720 | 236 | */ |
4b73005c | 237 | #define lxc_log_priority_define(acategory, LEVEL) \ |
cb8c5720 | 238 | \ |
4b73005c | 239 | ATTR_UNUSED static inline void LXC_##LEVEL(struct lxc_log_locinfo *, \ |
cb8c5720 CLG |
240 | const char *, ...) __attribute__ ((format (printf, 2, 3))); \ |
241 | \ | |
4b73005c | 242 | ATTR_UNUSED static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \ |
cb8c5720 CLG |
243 | const char* format, ...) \ |
244 | { \ | |
245 | if (lxc_log_priority_is_enabled(acategory, \ | |
4b73005c | 246 | LXC_LOG_LEVEL_##LEVEL)) { \ |
cb8c5720 CLG |
247 | struct lxc_log_event evt = { \ |
248 | .category = (acategory)->name, \ | |
4b73005c | 249 | .priority = LXC_LOG_LEVEL_##LEVEL, \ |
cb8c5720 CLG |
250 | .fmt = format, \ |
251 | .locinfo = locinfo \ | |
252 | }; \ | |
5fd8380b | 253 | va_list va_ref; \ |
cb8c5720 | 254 | \ |
c57dbb96 CB |
255 | /* clock_gettime() is explicitly marked as MT-Safe \ |
256 | * without restrictions. So let's use it for our \ | |
257 | * logging stamps. */ \ | |
258 | clock_gettime(CLOCK_REALTIME, &evt.timestamp); \ | |
cb8c5720 | 259 | \ |
5fd8380b MN |
260 | va_start(va_ref, format); \ |
261 | evt.vap = &va_ref; \ | |
cb8c5720 | 262 | __lxc_log(acategory, &evt); \ |
5fd8380b | 263 | va_end(va_ref); \ |
cb8c5720 CLG |
264 | } \ |
265 | } | |
266 | ||
267 | /* | |
268 | * Helper macro to define and use static categories. | |
269 | */ | |
270 | #define lxc_log_category_define(name, parent) \ | |
271 | extern struct lxc_log_category lxc_log_category_##parent; \ | |
272 | struct lxc_log_category lxc_log_category_##name = { \ | |
273 | #name, \ | |
4b73005c | 274 | LXC_LOG_LEVEL_NOTSET, \ |
cb8c5720 CLG |
275 | NULL, \ |
276 | &lxc_log_category_##parent \ | |
277 | }; | |
278 | ||
279 | #define lxc_log_define(name, parent) \ | |
280 | lxc_log_category_define(name, parent) \ | |
281 | \ | |
282 | lxc_log_priority_define(&lxc_log_category_##name, TRACE) \ | |
283 | lxc_log_priority_define(&lxc_log_category_##name, DEBUG) \ | |
284 | lxc_log_priority_define(&lxc_log_category_##name, INFO) \ | |
285 | lxc_log_priority_define(&lxc_log_category_##name, NOTICE) \ | |
286 | lxc_log_priority_define(&lxc_log_category_##name, WARN) \ | |
287 | lxc_log_priority_define(&lxc_log_category_##name, ERROR) \ | |
288 | lxc_log_priority_define(&lxc_log_category_##name, CRIT) \ | |
289 | lxc_log_priority_define(&lxc_log_category_##name, ALERT) \ | |
290 | lxc_log_priority_define(&lxc_log_category_##name, FATAL) | |
291 | ||
292 | #define lxc_log_category_priority(name) \ | |
293 | (lxc_log_priority_to_string(lxc_log_category_##name.priority)) | |
294 | ||
295 | /* | |
296 | * top categories | |
297 | */ | |
cb8c5720 CLG |
298 | #define TRACE(format, ...) do { \ |
299 | struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \ | |
300 | LXC_TRACE(&locinfo, format, ##__VA_ARGS__); \ | |
301 | } while (0) | |
302 | ||
303 | #define DEBUG(format, ...) do { \ | |
304 | struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \ | |
305 | LXC_DEBUG(&locinfo, format, ##__VA_ARGS__); \ | |
306 | } while (0) | |
307 | ||
308 | #define INFO(format, ...) do { \ | |
309 | struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \ | |
310 | LXC_INFO(&locinfo, format, ##__VA_ARGS__); \ | |
311 | } while (0) | |
312 | ||
313 | #define NOTICE(format, ...) do { \ | |
314 | struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \ | |
315 | LXC_NOTICE(&locinfo, format, ##__VA_ARGS__); \ | |
316 | } while (0) | |
317 | ||
318 | #define WARN(format, ...) do { \ | |
319 | struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \ | |
320 | LXC_WARN(&locinfo, format, ##__VA_ARGS__); \ | |
321 | } while (0) | |
322 | ||
323 | #define ERROR(format, ...) do { \ | |
324 | struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \ | |
325 | LXC_ERROR(&locinfo, format, ##__VA_ARGS__); \ | |
326 | } while (0) | |
327 | ||
328 | #define CRIT(format, ...) do { \ | |
329 | struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \ | |
330 | LXC_CRIT(&locinfo, format, ##__VA_ARGS__); \ | |
331 | } while (0) | |
332 | ||
333 | #define ALERT(format, ...) do { \ | |
334 | struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \ | |
335 | LXC_ALERT(&locinfo, format, ##__VA_ARGS__); \ | |
336 | } while (0) | |
337 | ||
338 | #define FATAL(format, ...) do { \ | |
339 | struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \ | |
340 | LXC_FATAL(&locinfo, format, ##__VA_ARGS__); \ | |
341 | } while (0) | |
342 | ||
343 | ||
344 | ||
345 | #define SYSERROR(format, ...) do { \ | |
69c3910d | 346 | ERROR("%s - " format, strerror(errno), ##__VA_ARGS__); \ |
cb8c5720 CLG |
347 | } while (0) |
348 | ||
641c20a6 CLG |
349 | extern int lxc_log_fd; |
350 | ||
858377e4 | 351 | extern int lxc_log_set_file(int *fd, const char *fname); |
64c57ea1 BD |
352 | extern int lxc_log_syslog(int facility); |
353 | extern void lxc_log_enable_syslog(void); | |
858377e4 | 354 | extern int lxc_log_set_level(int *dest, int level); |
ab1bf971 | 355 | extern void lxc_log_set_prefix(const char *prefix); |
9ea87d5d | 356 | extern const char *lxc_log_get_file(void); |
ab1bf971 | 357 | extern int lxc_log_get_level(void); |
fabf7361 | 358 | extern bool lxc_log_has_valid_level(void); |
ab1bf971 | 359 | extern const char *lxc_log_get_prefix(void); |
6edbfc86 | 360 | extern void lxc_log_options_no_override(); |
0ad19a3f | 361 | #endif |