2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
7 * Cedric Le Goater <legoater@free.fr>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
31 #define __USE_GNU /* for *_CLOEXEC */
40 #define LXC_LOG_PREFIX_SIZE 32
41 #define LXC_LOG_BUFFER_SIZE 512
44 static char log_prefix
[LXC_LOG_PREFIX_SIZE
] = "lxc";
45 static char *log_fname
= NULL
;
46 /* command line values for logfile or logpriority should always override
47 * values from the configuration file or defaults
49 static int lxc_logfile_specified
= 0;
50 static int lxc_loglevel_specified
= 0;
52 lxc_log_define(lxc_log
, lxc
);
54 /*---------------------------------------------------------------------------*/
55 static int log_append_stderr(const struct lxc_log_appender
*appender
,
56 struct lxc_log_event
*event
)
58 if (event
->priority
< LXC_LOG_PRIORITY_ERROR
)
61 fprintf(stderr
, "%s: ", log_prefix
);
62 vfprintf(stderr
, event
->fmt
, *event
->vap
);
63 fprintf(stderr
, "\n");
67 /*---------------------------------------------------------------------------*/
68 static int log_append_logfile(const struct lxc_log_appender
*appender
,
69 struct lxc_log_event
*event
)
71 char buffer
[LXC_LOG_BUFFER_SIZE
];
77 n
= snprintf(buffer
, sizeof(buffer
),
78 "%15s %10ld.%03ld %-8s %s - ",
80 event
->timestamp
.tv_sec
,
81 event
->timestamp
.tv_usec
/ 1000,
82 lxc_log_priority_to_string(event
->priority
),
85 n
+= vsnprintf(buffer
+ n
, sizeof(buffer
) - n
, event
->fmt
,
88 if (n
>= sizeof(buffer
) - 1) {
89 WARN("truncated next event from %d to %zd bytes", n
,
91 n
= sizeof(buffer
) - 1;
96 return write(lxc_log_fd
, buffer
, n
+ 1);
99 static struct lxc_log_appender log_appender_stderr
= {
101 .append
= log_append_stderr
,
105 static struct lxc_log_appender log_appender_logfile
= {
107 .append
= log_append_logfile
,
111 static struct lxc_log_category log_root
= {
113 .priority
= LXC_LOG_PRIORITY_ERROR
,
118 struct lxc_log_category lxc_log_category_lxc
= {
120 .priority
= LXC_LOG_PRIORITY_ERROR
,
121 .appender
= &log_appender_stderr
,
125 /*---------------------------------------------------------------------------*/
126 static int build_dir(const char *name
)
128 char *n
= strdup(name
); // because we'll be modifying it
133 ERROR("Out of memory while creating directory '%s'.", name
);
138 for (p
= n
+1; p
< e
; p
++) {
142 if (access(n
, F_OK
)) {
143 ret
= lxc_unpriv(mkdir(n
, 0755));
144 if (ret
&& errno
!= -EEXIST
) {
145 SYSERROR("failed to create directory '%s'.", n
);
156 /*---------------------------------------------------------------------------*/
157 static int log_open(const char *name
)
162 fd
= lxc_unpriv(open(name
, O_CREAT
| O_WRONLY
|
163 O_APPEND
| O_CLOEXEC
, 0666));
165 ERROR("failed to open log file \"%s\" : %s", name
,
173 newfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
175 ERROR("failed to dup log fd %d : %s", fd
, strerror(errno
));
182 * Build the path to the log file
183 * @name : the name of the container
184 * @lxcpath : the lxcpath to use as a basename or NULL to use LOGPATH
185 * Returns malloced path on sucess, or NULL on failure
187 static char *build_log_path(const char *name
, const char *lxcpath
)
190 int len
, ret
, use_dir
;
192 #if USE_CONFIGPATH_LOGS
199 * If USE_CONFIGPATH_LOGS is true or lxcpath is given, the resulting
201 * '$logpath' + '/' + '$name' + '/' + '$name' + '.log' + '\0'
203 * If USE_CONFIGPATH_LOGS is false the resulting path will be:
204 * '$logpath' + '/' + '$name' + '.log' + '\0'
206 len
= strlen(name
) + 6; /* 6 == '/' + '.log' + '\0' */
213 len
+= strlen(lxcpath
) + 1 + strlen(name
) + 1; /* add "/$container_name/" */
215 len
+= strlen(lxcpath
) + 1;
221 ret
= snprintf(p
, len
, "%s/%s/%s.log", lxcpath
, name
, name
);
223 ret
= snprintf(p
, len
, "%s/%s.log", lxcpath
, name
);
225 if (ret
< 0 || ret
>= len
) {
233 * This can be called:
234 * 1. when a program calls lxc_log_init with no logfile parameter (in which
235 * case the default is used). In this case lxc.logfile can override this.
236 * 2. when a program calls lxc_log_init with a logfile parameter. In this
237 * case we don't want lxc.logfile to override this.
238 * 3. When a lxc.logfile entry is found in config file.
240 static int __lxc_log_set_file(const char *fname
, int create_dirs
)
242 if (lxc_log_fd
!= -1) {
243 // we are overriding the default.
248 #if USE_CONFIGPATH_LOGS
249 // we don't build_dir for the default if the default is
250 // i.e. /var/lib/lxc/$container/$container.log
253 if (build_dir(fname
)) {
254 ERROR("failed to create dir for log file \"%s\" : %s", fname
,
259 lxc_log_fd
= log_open(fname
);
260 if (lxc_log_fd
== -1)
263 log_fname
= strdup(fname
);
267 static int _lxc_log_set_file(const char *name
, const char *lxcpath
, int create_dirs
)
272 logfile
= build_log_path(name
, lxcpath
);
274 ERROR("could not build log path");
277 ret
= __lxc_log_set_file(logfile
, create_dirs
);
282 extern int lxc_log_init(const char *name
, const char *file
,
283 const char *priority
, const char *prefix
, int quiet
,
286 int lxc_priority
= LXC_LOG_PRIORITY_ERROR
;
289 if (lxc_log_fd
!= -1) {
290 WARN("lxc_log_init called with log already initialized");
295 lxc_loglevel_specified
= 1;
296 lxc_priority
= lxc_log_priority_to_int(priority
);
298 if (lxc_priority
== LXC_LOG_PRIORITY_NOTSET
) {
299 ERROR("invalid log priority %s", priority
);
304 lxc_log_category_lxc
.priority
= lxc_priority
;
305 lxc_log_category_lxc
.appender
= &log_appender_logfile
;
308 lxc_log_category_lxc
.appender
->next
= &log_appender_stderr
;
311 lxc_log_set_prefix(prefix
);
314 lxc_logfile_specified
= 1;
315 if (strcmp(file
, "none") == 0)
317 ret
= __lxc_log_set_file(file
, 1);
321 /* try LOGPATH if lxcpath is the default */
322 if (strcmp(lxcpath
, default_lxc_path()) == 0)
323 ret
= _lxc_log_set_file(name
, NULL
, 0);
327 ret
= _lxc_log_set_file(name
, lxcpath
, 1);
329 /* try LOGPATH in case its writable by the caller */
331 ret
= _lxc_log_set_file(name
, NULL
, 0);
335 * If !file, that is, if the user did not request this logpath, then
336 * ignore failures and continue logging to console
338 if (!file
&& ret
!= 0) {
339 INFO("Ignoring failure to open default logfile.");
347 * This is called when we read a lxc.loglevel entry in a lxc.conf file. This
348 * happens after processing command line arguments, which override the .conf
349 * settings. So only set the level if previously unset.
351 extern int lxc_log_set_level(int level
)
353 if (lxc_loglevel_specified
)
355 if (level
< 0 || level
>= LXC_LOG_PRIORITY_NOTSET
) {
356 ERROR("invalid log priority %d", level
);
359 lxc_log_category_lxc
.priority
= level
;
363 extern int lxc_log_get_level(void)
365 if (!lxc_loglevel_specified
)
366 return LXC_LOG_PRIORITY_NOTSET
;
367 return lxc_log_category_lxc
.priority
;
371 * This is called when we read a lxc.logfile entry in a lxc.conf file. This
372 * happens after processing command line arguments, which override the .conf
373 * settings. So only set the file if previously unset.
375 extern int lxc_log_set_file(const char *fname
)
377 if (lxc_logfile_specified
)
379 return __lxc_log_set_file(fname
, 0);
382 extern const char *lxc_log_get_file(void)
387 extern void lxc_log_set_prefix(const char *prefix
)
389 strncpy(log_prefix
, prefix
, sizeof(log_prefix
));
390 log_prefix
[sizeof(log_prefix
) - 1] = 0;
393 extern const char *lxc_log_get_prefix(void)