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; }