diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
index 05baddd39..1f1fdb83c 100644
--- a/doc/lxc.container.conf.sgml.in
+++ b/doc/lxc.container.conf.sgml.in
@@ -1697,6 +1697,19 @@ mknod errno 0
+
+
+
+
+
+
+ Send logging info to syslog. It respects the log level defined in
+ lxc.loglevel. The argument should be the syslog
+ facility to use, valid ones are: daemon, local0, local1, local2,
+ local3, local4, local5, local5, local7.
+
+
+
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 14a76b2ec..645cac02d 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -38,6 +38,7 @@
#include
#include
#include
+#include
#include "parse.h"
#include "config.h"
@@ -105,6 +106,7 @@ static int config_haltsignal(const char *, const char *, struct lxc_conf *);
static int config_rebootsignal(const char *, const char *, struct lxc_conf *);
static int config_stopsignal(const char *, const char *, struct lxc_conf *);
static int config_start(const char *, const char *, struct lxc_conf *);
+static int config_syslog(const char *, const char *, struct lxc_conf *);
static int config_monitor(const char *, const char *, struct lxc_conf *);
static int config_group(const char *, const char *, struct lxc_conf *);
static int config_environment(const char *, const char *, struct lxc_conf *);
@@ -184,6 +186,7 @@ static struct lxc_config_t config[] = {
{ "lxc.init_uid", config_init_uid },
{ "lxc.init_gid", config_init_gid },
{ "lxc.ephemeral", config_ephemeral },
+ { "lxc.syslog", config_syslog },
};
struct signame {
@@ -270,6 +273,23 @@ static const struct signame signames[] = {
#endif
};
+struct syslog_facility {
+ const char *name;
+ int facility;
+};
+
+static const struct syslog_facility syslog_facilities[] = {
+ { "daemon", LOG_DAEMON },
+ { "local0", LOG_LOCAL0 },
+ { "local1", LOG_LOCAL1 },
+ { "local2", LOG_LOCAL2 },
+ { "local3", LOG_LOCAL3 },
+ { "local4", LOG_LOCAL4 },
+ { "local5", LOG_LOCAL5 },
+ { "local6", LOG_LOCAL6 },
+ { "local7", LOG_LOCAL7 },
+};
+
static const size_t config_size = sizeof(config)/sizeof(struct lxc_config_t);
extern struct lxc_config_t *lxc_getconfig(const char *key)
@@ -2919,3 +2939,20 @@ static int config_ephemeral(const char *key, const char *value,
return 0;
}
+static int config_syslog(const char *key, const char *value,
+ struct lxc_conf *lxc_conf)
+{
+ int n;
+ int facility = -1;
+
+ for (n = 0; n < sizeof(syslog_facilities) / sizeof((syslog_facilities)[0]); n++) {
+ if (strcasecmp(syslog_facilities[n].name, value) == 0) {
+ facility = syslog_facilities[n].facility;
+ lxc_log_syslog(facility);
+ return 0;
+ }
+ }
+
+ ERROR("Wrong value for lxc.syslog");
+ return -1;
+}
diff --git a/src/lxc/log.c b/src/lxc/log.c
index 11d4bbfb5..d7db033a2 100644
--- a/src/lxc/log.c
+++ b/src/lxc/log.c
@@ -33,6 +33,9 @@
#define __USE_GNU /* for *_CLOEXEC */
+#include
+#include
+
#include
#include
@@ -43,15 +46,78 @@
#define LXC_LOG_DATEFOMAT_SIZE 15
int lxc_log_fd = -1;
+static int syslog_enable = 0;
int lxc_quiet_specified;
int lxc_log_use_global_fd;
static int lxc_loglevel_specified;
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
static char *log_fname = NULL;
+static char *log_vmname = NULL;
lxc_log_define(lxc_log, lxc);
+static int lxc_log_priority_to_syslog(int priority)
+{
+ switch (priority) {
+ case LXC_LOG_PRIORITY_FATAL:
+ return LOG_EMERG;
+ case LXC_LOG_PRIORITY_ALERT:
+ return LOG_ALERT;
+ case LXC_LOG_PRIORITY_CRIT:
+ return LOG_CRIT;
+ case LXC_LOG_PRIORITY_ERROR:
+ return LOG_ERR;
+ case LXC_LOG_PRIORITY_WARN:
+ return LOG_WARNING;
+ case LXC_LOG_PRIORITY_NOTICE:
+ case LXC_LOG_PRIORITY_NOTSET:
+ return LOG_NOTICE;
+ case LXC_LOG_PRIORITY_INFO:
+ return LOG_INFO;
+ case LXC_LOG_PRIORITY_TRACE:
+ case LXC_LOG_PRIORITY_DEBUG:
+ return LOG_DEBUG;
+ }
+
+ /* Not reached */
+ return LOG_NOTICE;
+}
+
+/*---------------------------------------------------------------------------*/
+static int log_append_syslog(const struct lxc_log_appender *appender,
+ struct lxc_log_event *event)
+{
+ char *msg;
+ int rc, len;
+ va_list args;
+
+ if (!syslog_enable)
+ return 0;
+
+ va_copy(args, *event->vap);
+ len = vsnprintf(NULL, 0, event->fmt, args) + 1;
+ va_end(args);
+ msg = malloc(len * sizeof(char));
+ if (msg == NULL)
+ return 0;
+ rc = vsnprintf(msg, len, event->fmt, *event->vap);
+ if (rc == -1 || rc >= len) {
+ free(msg);
+ return 0;
+ }
+
+ syslog(lxc_log_priority_to_syslog(event->priority),
+ "%s %s - %s:%s:%d - %s" ,
+ log_vmname ? log_vmname : "",
+ event->category,
+ event->locinfo->file, event->locinfo->func,
+ event->locinfo->line,
+ msg);
+ free(msg);
+ return 0;
+}
+
/*---------------------------------------------------------------------------*/
static int log_append_stderr(const struct lxc_log_appender *appender,
struct lxc_log_event *event)
@@ -59,7 +125,7 @@ static int log_append_stderr(const struct lxc_log_appender *appender,
if (event->priority < LXC_LOG_PRIORITY_ERROR)
return 0;
- fprintf(stderr, "%s: ", log_prefix);
+ fprintf(stderr, "%s: %s", log_prefix, log_vmname ? log_vmname : "");
fprintf(stderr, "%s: %s: %d ", event->locinfo->file, event->locinfo->func, event->locinfo->line);
vfprintf(stderr, event->fmt, *event->vap);
fprintf(stderr, "\n");
@@ -92,8 +158,10 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
strftime(date, sizeof(date), "%Y%m%d%H%M%S", t);
ms = event->timestamp.tv_usec / 1000;
n = snprintf(buffer, sizeof(buffer),
- "%15s %10s.%03d %-8s %s - %s:%s:%d - ",
+ "%15s%s%s %10s.%03d %-8s %s - %s:%s:%d - ",
log_prefix,
+ log_vmname ? " " : "",
+ log_vmname ? log_vmname : "",
date,
ms,
lxc_log_priority_to_string(event->priority),
@@ -115,6 +183,12 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
return write(fd_to_use, buffer, n + 1);
}
+static struct lxc_log_appender log_appender_syslog = {
+ .name = "syslog",
+ .append = log_append_syslog,
+ .next = NULL,
+};
+
static struct lxc_log_appender log_appender_stderr = {
.name = "stderr",
.append = log_append_stderr,
@@ -253,6 +327,9 @@ static char *build_log_path(const char *name, const char *lxcpath)
extern void lxc_log_close(void)
{
+ closelog();
+ free(log_vmname);
+ log_vmname = NULL;
if (lxc_log_fd == -1)
return;
close(lxc_log_fd);
@@ -317,6 +394,28 @@ static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_d
return ret;
}
+extern int lxc_log_syslog(int facility)
+{
+ struct lxc_log_appender *appender;
+
+ openlog(log_prefix, LOG_PID, facility);
+ if (!lxc_log_category_lxc.appender) {
+ lxc_log_category_lxc.appender = &log_appender_syslog;
+ return 0;
+ }
+ appender = lxc_log_category_lxc.appender;
+ while (appender->next != NULL)
+ appender = appender->next;
+ appender->next = &log_appender_syslog;
+
+ return 0;
+}
+
+extern void lxc_log_enable_syslog(void)
+{
+ syslog_enable = 1;
+}
+
/*
* lxc_log_init:
* Called from lxc front-end programs (like lxc-create, lxc-start) to
@@ -350,6 +449,9 @@ extern int lxc_log_init(const char *name, const char *file,
if (prefix)
lxc_log_set_prefix(prefix);
+ if (name)
+ log_vmname = strdup(name);
+
if (file) {
if (strcmp(file, "none") == 0)
return 0;
diff --git a/src/lxc/log.h b/src/lxc/log.h
index eb330d0b1..8906c234d 100644
--- a/src/lxc/log.h
+++ b/src/lxc/log.h
@@ -314,6 +314,8 @@ extern int lxc_log_init(const char *name, const char *file,
const char *lxcpath);
extern int lxc_log_set_file(int *fd, const char *fname);
+extern int lxc_log_syslog(int facility);
+extern void lxc_log_enable_syslog(void);
extern int lxc_log_set_level(int *dest, int level);
extern void lxc_log_set_prefix(const char *prefix);
extern const char *lxc_log_get_file(void);
diff --git a/src/lxc/start.c b/src/lxc/start.c
index b3f75b8e1..1ba0f9bd7 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -255,6 +255,13 @@ restart:
WARN("inherited fd %d", fd);
}
+ /*
+ * only enable syslog at this point to avoid the above logging function
+ * to open a new fd and make the check_inherited function enter an
+ * infinite loop.
+ */
+ lxc_log_enable_syslog();
+
closedir(dir); /* cannot fail */
return 0;
}