[lxc-devel] [PATCH RFC] log: introduce container logging

Serge Hallyn serge.hallyn at ubuntu.com
Wed Mar 12 00:13:04 UTC 2014


This is not intended to be applied yet.

This patch adds real per-container, thread-safe log preferences.  Currently
if a program loads two containers which both set a lxc.logfile, and start
then start them in sequence, the logfile for the second container will be
used.  This patch stores the log preferences in the lxc_container itself.
It leaves ERROR/INFO/etc as global log print helpers, while the new
CERROR/CINFO/etc become new per-container helpers.  To demonstrate how to
use these, some logging in lxcapi_start and lxcapi_create has been
converted.

What this patch ignores, and why I say this patch is not ready to be
applied, is what to do about 'lxc-start -l info -o outfile'.  With this
patch, global logging (ERROR) will go to outfile, while per-container
logging will not.

If we want the options provided to lxc-start to override what is in
the container config file, perhaps lxc-start should simply call
c->set_config_item("lxc.logfile", "outfile") right before lxc-start?
Or should we say that the container configuration file values
override command line values?  (I don't think that makes a lot of sense
as an end-user)

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/confile.c      |  15 ++---
 src/lxc/log.c          | 145 ++++++++++++++++++++++++++++++++-----------------
 src/lxc/log.h          | 117 ++++++++++++++++++++++++++++++---------
 src/lxc/lxccontainer.c |  93 ++++++++++++++++---------------
 src/lxc/lxccontainer.h |   7 +++
 5 files changed, 246 insertions(+), 131 deletions(-)

diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 8b1c0b6..9eeb90b 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -1089,14 +1089,7 @@ static int config_lsm_se_context(const char *key, const char *value,
 static int config_logfile(const char *key, const char *value,
 			     struct lxc_conf *lxc_conf)
 {
-	int ret;
-
-	// store these values in the lxc_conf, and then try to set for
-	// actual current logging.
-	ret = config_path_item(&lxc_conf->logfile, value);
-	if (ret == 0)
-		ret = lxc_log_set_file(lxc_conf->logfile);
-	return ret;
+	return config_path_item(&lxc_conf->logfile, value);
 }
 
 static int config_loglevel(const char *key, const char *value,
@@ -1114,7 +1107,7 @@ static int config_loglevel(const char *key, const char *value,
 	// store these values in the lxc_conf, and then try to set for
 	// actual current logging.
 	lxc_conf->loglevel = newlevel;
-	return lxc_log_set_level(newlevel);
+	return 0;
 }
 
 static int config_autodev(const char *key, const char *value,
@@ -2089,9 +2082,9 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
 	else if (strcmp(key, "lxc.se_context") == 0)
 		v = c->lsm_se_context;
 	else if (strcmp(key, "lxc.logfile") == 0)
-		v = lxc_log_get_file();
+		v = c->logfile;
 	else if (strcmp(key, "lxc.loglevel") == 0)
-		v = lxc_log_priority_to_string(lxc_log_get_level());
+		v = lxc_log_priority_to_string(c->loglevel);
 	else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info
 		return lxc_get_cgroup_entry(c, retv, inlen, "all");
 	else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info
diff --git a/src/lxc/log.c b/src/lxc/log.c
index d5b862e..a8ddc44 100644
--- a/src/lxc/log.c
+++ b/src/lxc/log.c
@@ -40,16 +40,6 @@
 #define LXC_LOG_PREFIX_SIZE	32
 #define LXC_LOG_BUFFER_SIZE	512
 
-#ifdef HAVE_TLS
-__thread int lxc_log_fd = -1;
-static __thread char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
-static __thread char *log_fname = NULL;
-/* command line values for logfile or logpriority should always override
- * values from the configuration file or defaults
- */
-static __thread int lxc_logfile_specified = 0;
-static __thread int lxc_loglevel_specified = 0;
-#else
 int lxc_log_fd = -1;
 static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
 static char *log_fname = NULL;
@@ -58,13 +48,12 @@ static char *log_fname = NULL;
  */
 static int lxc_logfile_specified = 0;
 static int lxc_loglevel_specified = 0;
-#endif
 
 lxc_log_define(lxc_log, lxc);
 
 /*---------------------------------------------------------------------------*/
 static int log_append_stderr(const struct lxc_log_appender *appender,
-			     struct lxc_log_event *event)
+		int log_fd, struct lxc_log_event *event)
 {
 	if (event->priority < LXC_LOG_PRIORITY_ERROR)
 		return 0;
@@ -77,13 +66,15 @@ static int log_append_stderr(const struct lxc_log_appender *appender,
 
 /*---------------------------------------------------------------------------*/
 static int log_append_logfile(const struct lxc_log_appender *appender,
-			      struct lxc_log_event *event)
+		int log_fd, struct lxc_log_event *event)
 {
 	char buffer[LXC_LOG_BUFFER_SIZE];
 	int n;
 	int ms;
 
-	if (lxc_log_fd == -1)
+	if (log_fd == -1)
+		log_fd = lxc_log_fd;
+	if (log_fd == -1)
 		return 0;
 
 	ms = event->timestamp.tv_usec / 1000;
@@ -106,7 +97,7 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
 
 	buffer[n] = '\n';
 
-	return write(lxc_log_fd, buffer, n + 1);
+	return write(log_fd, buffer, n + 1);
 }
 
 static struct lxc_log_appender log_appender_stderr = {
@@ -121,18 +112,26 @@ static struct lxc_log_appender log_appender_logfile = {
 	.next		= NULL,
 };
 
+static struct lxc_log_appender c_log_appender_logfile = {
+	.name		= "logfile",
+	.append		= log_append_logfile,
+	.next		= NULL,
+};
+
 static struct lxc_log_category log_root = {
 	.name		= "root",
 	.priority	= LXC_LOG_PRIORITY_ERROR,
 	.appender	= NULL,
 	.parent		= NULL,
+	.log_fd		= -1,
 };
 
 struct lxc_log_category lxc_log_category_lxc = {
 	.name		= "lxc",
 	.priority	= LXC_LOG_PRIORITY_ERROR,
 	.appender	= &log_appender_stderr,
-	.parent		= &log_root
+	.parent		= &log_root,
+	.log_fd		= -1,
 };
 
 /*---------------------------------------------------------------------------*/
@@ -368,6 +367,86 @@ extern int lxc_log_init(const char *name, const char *file,
 	return ret;
 }
 
+extern const char *lxc_log_get_file(void)
+{
+	return log_fname;
+}
+
+#include <lxccontainer.h>
+
+extern void container_log_close(struct lxc_container *c)
+{
+	if (c->log_category) {
+		if (c->log_category->log_fd != -1)
+			close(c->log_category->log_fd);
+		free(c->log_category);
+		c->log_category = NULL;
+	}
+	free(c->log_file);
+}
+
+static bool logfile_unchanged(struct lxc_container *c, int lvl)
+{
+	int oldlvl = LXC_LOG_PRIORITY_NOTSET;
+
+	if (c->log_category)
+		oldlvl = c->log_category->priority;
+	if (oldlvl != lvl)
+		return false;
+	if (!c->log_file && !c->lxc_conf->logfile)
+		return true;
+	if (!c->log_file || !c->lxc_conf->logfile)
+		return true;
+	return (strcmp(c->log_file, c->lxc_conf->logfile) == 0);
+}
+
+extern bool container_log_init(struct lxc_container *c)
+{
+	int lvl = c->lxc_conf->loglevel;
+	struct lxc_log_category *category;
+	const char *file = c->lxc_conf->logfile;
+
+	if (logfile_unchanged(c, lvl))
+		return true;
+
+	container_log_close(c);
+
+	if (file) {
+		c->log_file = strdup(file);
+		if (!c->log_file) {
+			ERROR("%s: out of memory", __func__);
+			return false;
+		}
+	}
+
+	category = malloc(sizeof(*category));
+	if (!category) {
+		ERROR("%s: out of memory", __func__);
+		return false;
+	}
+
+	category->appender = &c_log_appender_logfile;
+	category->name = "container",
+	category->priority = lvl;
+	category->parent = NULL;
+	c->log_category = category;
+
+	if (!file || strcmp(file, "none") == 0)
+		return true;
+
+	if (build_dir(file)) {
+		ERROR("failed to create dir for log file \"%s\" : %s", file,
+		      strerror(errno));
+		return false;
+	}
+
+	c->log_category->log_fd = log_open(file);
+	if (c->log_category->log_fd == -1)
+		return false;
+
+	return true;
+}
+
 extern void lxc_log_close(void)
 {
 	if (lxc_log_fd == -1)
@@ -378,23 +457,6 @@ extern void lxc_log_close(void)
 	log_fname = NULL;
 }
 
-/*
- * This is called when we read a lxc.loglevel entry in a lxc.conf file.  This
- * happens after processing command line arguments, which override the .conf
- * settings.  So only set the level if previously unset.
- */
-extern int lxc_log_set_level(int level)
-{
-	if (lxc_loglevel_specified)
-		return 0;
-	if (level < 0 || level >= LXC_LOG_PRIORITY_NOTSET) {
-		ERROR("invalid log priority %d", level);
-		return -1;
-	}
-	lxc_log_category_lxc.priority = level;
-	return 0;
-}
-
 extern int lxc_log_get_level(void)
 {
 	return lxc_log_category_lxc.priority;
@@ -408,23 +470,6 @@ extern bool lxc_log_has_valid_level(void)
 	return true;
 }
 
-/*
- * This is called when we read a lxc.logfile entry in a lxc.conf file.  This
- * happens after processing command line arguments, which override the .conf
- * settings.  So only set the file if previously unset.
- */
-extern int lxc_log_set_file(const char *fname)
-{
-	if (lxc_logfile_specified)
-		return 0;
-	return __lxc_log_set_file(fname, 0);
-}
-
-extern const char *lxc_log_get_file(void)
-{
-	return log_fname;
-}
-
 extern void lxc_log_set_prefix(const char *prefix)
 {
 	strncpy(log_prefix, prefix, sizeof(log_prefix));
diff --git a/src/lxc/log.h b/src/lxc/log.h
index 5252869..9097ffa 100644
--- a/src/lxc/log.h
+++ b/src/lxc/log.h
@@ -25,6 +25,8 @@
 #define _log_h
 
 #include "config.h"
+#include <lxccontainer.h>
+#include "conf.h"
 
 #include <stdarg.h>
 #include <stdio.h>
@@ -81,7 +83,7 @@ struct lxc_log_event {
 /* log appender object */
 struct lxc_log_appender {
 	const char*	name;
-	int (*append)(const struct lxc_log_appender *, struct lxc_log_event *);
+	int (*append)(const struct lxc_log_appender *, int log_fd, struct lxc_log_event *);
 
 	/*
 	 * appenders can be stacked
@@ -95,6 +97,11 @@ struct lxc_log_category {
 	int				priority;
 	struct lxc_log_appender		*appender;
 	const struct lxc_log_category	*parent;
+	/*
+	 * if this is a container log_category, store log_fd here
+	 * else use lxc_log_fd
+	 */
+	int log_fd;
 };
 
 /*
@@ -102,9 +109,11 @@ struct lxc_log_category {
  * given priority.
  */
 static inline int
-lxc_log_priority_is_enabled(const struct lxc_log_category* category,
-			   int priority)
+lxc_log_priority_is_enabled(struct lxc_container *c,
+		const struct lxc_log_category* category, int priority)
 {
+	if (c && c->log_category)
+		category = c->log_category;
 	while (category->priority == LXC_LOG_PRIORITY_NOTSET &&
 	       category->parent)
 		category = category->parent;
@@ -150,7 +159,7 @@ static inline int lxc_log_priority_to_int(const char* name)
 }
 
 static inline void
-__lxc_log_append(const struct lxc_log_appender *appender,
+__lxc_log_append(const struct lxc_log_appender *appender, int fd,
 		struct lxc_log_event* event)
 {
 	va_list va, *va_keep;
@@ -159,18 +168,21 @@ __lxc_log_append(const struct lxc_log_appender *appender,
 	while (appender) {
 		va_copy(va, *va_keep);
 		event->vap = &va;
-		appender->append(appender, event);
+		appender->append(appender, fd, event);
 		appender = appender->next;
 		va_end(va);
 	}
 }
 
 static inline void
-__lxc_log(const struct lxc_log_category* category,
-	  struct lxc_log_event* event)
+__lxc_log(struct lxc_container *c,
+		const struct lxc_log_category* category,
+		struct lxc_log_event* event)
 {
+	if (c && c->log_category)
+		category =  c->log_category;
 	while (category) {
-		__lxc_log_append(category->appender, event);
+		__lxc_log_append(category->appender, category->log_fd, event);
 		category = category->parent;
 	}
 }
@@ -180,13 +192,15 @@ __lxc_log(const struct lxc_log_category* category,
  */
 #define lxc_log_priority_define(acategory, PRIORITY)			\
 									\
-static inline void LXC_##PRIORITY(struct lxc_log_locinfo *,		\
-	const char *, ...) __attribute__ ((format (printf, 2, 3)));	\
+static inline void LXC_##PRIORITY(struct lxc_container *c,		\
+		struct lxc_log_locinfo *, const char *, ...)		\
+		__attribute__ ((format (printf, 3, 4)));		\
 									\
-static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo,	\
+static inline void LXC_##PRIORITY(struct lxc_container *c,		\
+				  struct lxc_log_locinfo* locinfo,	\
 				  const char* format, ...)		\
 {									\
-	if (lxc_log_priority_is_enabled(acategory, 			\
+	if (lxc_log_priority_is_enabled(c, acategory, 		\
 					LXC_LOG_PRIORITY_##PRIORITY)) {	\
 		struct lxc_log_event evt = {				\
 			.category	= (acategory)->name,		\
@@ -200,7 +214,7 @@ static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo,	\
 									\
 		va_start(va_ref, format);				\
 		evt.vap = &va_ref;					\
-		__lxc_log(acategory, &evt);				\
+		__lxc_log(c, acategory, &evt);				\
 		va_end(va_ref);						\
 	}								\
 }
@@ -238,47 +252,47 @@ static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo,	\
  */
 #define TRACE(format, ...) do {						\
 	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
-	LXC_TRACE(&locinfo, format, ##__VA_ARGS__);			\
+	LXC_TRACE(NULL, &locinfo, format, ##__VA_ARGS__);		\
 } while (0)
 
 #define DEBUG(format, ...) do {						\
 	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
-	LXC_DEBUG(&locinfo, format, ##__VA_ARGS__);			\
+	LXC_DEBUG(NULL, &locinfo, format, ##__VA_ARGS__);		\
 } while (0)
 
 #define INFO(format, ...) do {						\
 	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
-	LXC_INFO(&locinfo, format, ##__VA_ARGS__);			\
+	LXC_INFO(NULL, &locinfo, format, ##__VA_ARGS__);		\
 } while (0)
 
 #define NOTICE(format, ...) do {					\
 	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
-	LXC_NOTICE(&locinfo, format, ##__VA_ARGS__);			\
+	LXC_NOTICE(NULL, &locinfo, format, ##__VA_ARGS__);		\
 } while (0)
 
 #define WARN(format, ...) do {						\
 	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
-	LXC_WARN(&locinfo, format, ##__VA_ARGS__);			\
+	LXC_WARN(NULL, &locinfo, format, ##__VA_ARGS__);		\
 } while (0)
 
 #define ERROR(format, ...) do {						\
 	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
-	LXC_ERROR(&locinfo, format, ##__VA_ARGS__);			\
+	LXC_ERROR(NULL, &locinfo, format, ##__VA_ARGS__);		\
 } while (0)
 
 #define CRIT(format, ...) do {						\
 	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
-	LXC_CRIT(&locinfo, format, ##__VA_ARGS__);			\
+	LXC_CRIT(NULL, &locinfo, format, ##__VA_ARGS__);		\
 } while (0)
 
 #define ALERT(format, ...) do {						\
 	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
-	LXC_ALERT(&locinfo, format, ##__VA_ARGS__);			\
+	LXC_ALERT(NULL, &locinfo, format, ##__VA_ARGS__);		\
 } while (0)
 
 #define FATAL(format, ...) do {						\
 	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
-	LXC_FATAL(&locinfo, format, ##__VA_ARGS__);			\
+	LXC_FATAL(NULL, &locinfo, format, ##__VA_ARGS__);		\
 } while (0)
 
 
@@ -287,11 +301,60 @@ static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo,	\
 	ERROR("%s - " format, strerror(errno), ##__VA_ARGS__);		\
 } while (0)
 
-#ifdef HAVE_TLS
-extern __thread int lxc_log_fd;
-#else
+
+/* container logging versions */
+#define CTRACE(c, format, ...) do {					\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_TRACE(c, &locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+#define CDEBUG(c, format, ...) do {					\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_DEBUG(c, &locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+#define CINFO(c, format, ...) do {					\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_INFO(c, &locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+#define CNOTICE(c, format, ...) do {					\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_NOTICE(c, &locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+#define CWARN(c, format, ...) do {					\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_WARN(c, &locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+#define CERROR(c, format, ...) do {					\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_ERROR(c, &locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+#define CCRIT(c, format, ...) do {					\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_CRIT(c, &locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+#define CALERT(c, format, ...) do {					\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_ALERT(c, &locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+#define CFATAL(c, format, ...) do {					\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_FATAL(c, &locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+
+
+#define CSYSERROR(c, format, ...) do {				    	\
+	CERROR(c, "%s - " format, strerror(errno), ##__VA_ARGS__);	\
+} while (0)
+
 extern int lxc_log_fd;
-#endif
 
 extern int lxc_log_init(const char *name, const char *file,
 			const char *priority, const char *prefix, int quiet,
@@ -305,4 +368,6 @@ extern int lxc_log_get_level(void);
 extern bool lxc_log_has_valid_level(void);
 extern const char *lxc_log_get_prefix(void);
 extern void lxc_log_options_no_override();
+extern bool container_log_init(struct lxc_container *c);
+extern void container_log_close(struct lxc_container *c);
 #endif
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index c90b564..3d35bb0 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -250,6 +250,8 @@ static void lxc_container_free(struct lxc_container *c)
 		c->config_path = NULL;
 	}
 
+	container_log_close(c);
+
 	free(c);
 }
 
@@ -415,11 +417,16 @@ static pid_t lxcapi_init_pid(struct lxc_container *c)
 
 static bool load_config_locked(struct lxc_container *c, const char *fname)
 {
+	bool bret = false;
 	if (!c->lxc_conf)
 		c->lxc_conf = lxc_conf_init();
 	if (c->lxc_conf && !lxc_config_read(fname, c->lxc_conf))
-		return true;
-	return false;
+		bret = true;
+	/* If the logfile/level have been set, we need to update those */
+	if (!container_log_init(c))
+		ERROR("Failed to set the requested log settings");
+
+	return bret;
 }
 
 static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file)
@@ -464,7 +471,7 @@ static bool lxcapi_want_daemonize(struct lxc_container *c, bool state)
 	if (!c || !c->lxc_conf)
 		return false;
 	if (container_mem_lock(c)) {
-		ERROR("Error getting mem lock");
+		CERROR(c, "Error getting mem lock");
 		return false;
 	}
 	c->daemonize = state;
@@ -480,7 +487,7 @@ static bool lxcapi_want_close_all_fds(struct lxc_container *c, bool state)
 	if (!c || !c->lxc_conf)
 		return false;
 	if (container_mem_lock(c)) {
-		ERROR("Error getting mem lock");
+		CERROR(c, "Error getting mem lock");
 		return false;
 	}
 	c->lxc_conf->close_all_fds = state;
@@ -511,11 +518,11 @@ static bool wait_on_daemonized_start(struct lxc_container *c, int pid)
 	 */
 	ret = waitpid(pid, &status, 0);
 	if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
-		DEBUG("failed waiting for first dual-fork child");
+		CDEBUG(c, "failed waiting for first dual-fork child");
 	return lxcapi_wait(c, "RUNNING", timeout);
 }
 
-static bool am_single_threaded(void)
+static bool am_single_threaded(struct lxc_container *c)
 {
 	struct dirent dirent, *direntp;
 	DIR *dir;
@@ -523,7 +530,7 @@ static bool am_single_threaded(void)
 
 	dir = opendir("/proc/self/task");
 	if (!dir) {
-		INFO("failed to open /proc/self/task");
+		CINFO(c, "failed to open /proc/self/task");
 		return false;
 	}
 
@@ -566,15 +573,15 @@ static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv
 		return false;
 
 	if ((ret = ongoing_create(c)) < 0) {
-		ERROR("Error checking for incomplete creation");
+		CERROR(c, "Error checking for incomplete creation");
 		return false;
 	}
 	if (ret == 2) {
-		ERROR("Error: %s creation was not completed", c->name);
+		CERROR(c, "Error: %s creation was not completed", c->name);
 		c->destroy(c);
 		return false;
 	} else if (ret == 1) {
-		ERROR("Error: creation of %s is ongoing", c->name);
+		CERROR(c, "Error: creation of %s is ongoing", c->name);
 		return false;
 	}
 
@@ -620,14 +627,14 @@ static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv
 		/* second fork to be reparented by init */
 		pid = fork();
 		if (pid < 0) {
-			SYSERROR("Error doing dual-fork");
+			CSYSERROR(c, "Error doing dual-fork");
 			return false;
 		}
 		if (pid != 0)
 			exit(0);
 		/* like daemon(), chdir to / and redirect 0,1,2 to /dev/null */
 		if (chdir("/")) {
-			SYSERROR("Error chdir()ing to /.");
+			CSYSERROR(c, "Error chdir()ing to /.");
 			return false;
 		}
 		close(0);
@@ -638,7 +645,7 @@ static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv
 		open("/dev/null", O_RDWR);
 		setsid();
 	} else {
-		if (!am_single_threaded()) {
+		if (!am_single_threaded(c)) {
 			ERROR("Cannot start non-daemonized container when threaded");
 			return false;
 		}
@@ -650,13 +657,13 @@ static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv
 	if (c->pidfile) {
 		pid_fp = fopen(c->pidfile, "w");
 		if (pid_fp == NULL) {
-			SYSERROR("Failed to create pidfile '%s' for '%s'",
+			CSYSERROR(c, "Failed to create pidfile '%s' for '%s'",
 				 c->pidfile, c->name);
 			return false;
 		}
 
 		if (fprintf(pid_fp, "%d\n", getpid()) < 0) {
-			SYSERROR("Failed to write '%s'", c->pidfile);
+			CSYSERROR(c, "Failed to write '%s'", c->pidfile);
 			fclose(pid_fp);
 			pid_fp = NULL;
 			return false;
@@ -671,7 +678,7 @@ reboot:
 	ret = lxc_start(c->name, argv, conf, c->config_path);
 
 	if (conf->reboot) {
-		INFO("container requested reboot");
+		CINFO(c, "container requested reboot");
 		conf->reboot = 0;
 		goto reboot;
 	}
@@ -706,7 +713,7 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
 	va_end(ap);
 
 	if (!inargs) {
-		ERROR("Memory allocation error.");
+		CERROR(c, "Memory allocation error.");
 		goto out;
 	}
 
@@ -758,7 +765,7 @@ static bool create_container_dir(struct lxc_container *c)
 		if (errno == EEXIST)
 			ret = 0;
 		else
-			SYSERROR("failed to create container path for %s", c->name);
+			CSYSERROR(c, "failed to create container path for %s", c->name);
 	}
 	free(s);
 	return ret == 0;
@@ -796,7 +803,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
 
 	bdev = bdev_create(dest, type, c->name, specs);
 	if (!bdev) {
-		ERROR("Failed to create backing store type %s", type);
+		CERROR(c, "Failed to create backing store type %s", type);
 		return NULL;
 	}
 
@@ -807,7 +814,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
 
 	if (geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) {
 		if (chown_mapped_root(bdev->dest, c->lxc_conf) < 0) {
-			ERROR("Error chowning %s to container root", bdev->dest);
+			CERROR(c, "Error chowning %s to container root", bdev->dest);
 			bdev_put(bdev);
 			return NULL;
 		}
@@ -868,7 +875,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
 
 	pid = fork();
 	if (pid < 0) {
-		SYSERROR("failed to fork task for container creation template");
+		CSYSERROR(c, "failed to fork task for container creation template");
 		return false;
 	}
 
@@ -902,29 +909,29 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
 
 		bdev = bdev_init(src, c->lxc_conf->rootfs.mount, NULL);
 		if (!bdev) {
-			ERROR("Error opening rootfs");
+			CERROR(c, "Error opening rootfs");
 			exit(1);
 		}
 
 		if (geteuid() == 0) {
 			if (unshare(CLONE_NEWNS) < 0) {
-				ERROR("error unsharing mounts");
+				CERROR(c, "error unsharing mounts");
 				exit(1);
 			}
 			if (detect_shared_rootfs()) {
 				if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
-					SYSERROR("Failed to make / rslave to run template");
-					ERROR("Continuing...");
+					CSYSERROR(c, "Failed to make / rslave to run template");
+					CERROR(c, "Continuing...");
 				}
 			}
 		}
 		if (strcmp(bdev->type, "dir") != 0) {
 			if (geteuid() != 0) {
-				ERROR("non-root users can only create directory-backed containers");
+				CERROR(c, "non-root users can only create directory-backed containers");
 				exit(1);
 			}
 			if (bdev->ops->mount(bdev) < 0) {
-				ERROR("Error mounting rootfs");
+				CERROR(c, "Error mounting rootfs");
 				exit(1);
 			}
 		} else { // TODO come up with a better way here!
@@ -1000,7 +1007,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
 			struct id_map *map;
 
 			if (!n2) {
-				SYSERROR("out of memory");
+				CSYSERROR(c, "out of memory");
 				exit(1);
 			}
 			newargv[0] = tpath;
@@ -1031,18 +1038,18 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
 				hostid_mapped = find_unmapped_nsuid(conf, ID_TYPE_UID);
 				n2[n2args++] = "-m";
 				if (hostid_mapped < 0) {
-					ERROR("Could not find free uid to map");
+					CERROR(c, "Could not find free uid to map");
 					exit(1);
 				}
 				n2[n2args++] = malloc(200);
 				if (!n2[n2args-1]) {
-					SYSERROR("out of memory");
+					CSYSERROR(c, "out of memory");
 					exit(1);
 				}
 				ret = snprintf(n2[n2args-1], 200, "u:%d:%d:1",
 					hostid_mapped, geteuid());
 				if (ret < 0 || ret >= 200) {
-					ERROR("string too long");
+					CERROR(c, "string too long");
 					exit(1);
 				}
 			}
@@ -1055,18 +1062,18 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
 				hostgid_mapped = find_unmapped_nsuid(conf, ID_TYPE_GID);
 				n2[n2args++] = "-m";
 				if (hostgid_mapped < 0) {
-					ERROR("Could not find free uid to map");
+					CERROR(c, "Could not find free uid to map");
 					exit(1);
 				}
 				n2[n2args++] = malloc(200);
 				if (!n2[n2args-1]) {
-					SYSERROR("out of memory");
+					CSYSERROR(c, "out of memory");
 					exit(1);
 				}
 				ret = snprintf(n2[n2args-1], 200, "g:%d:%d:1",
 					hostgid_mapped, getegid());
 				if (ret < 0 || ret >= 200) {
-					ERROR("string too long");
+					CERROR(c, "string too long");
 					exit(1);
 				}
 			}
@@ -1079,7 +1086,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
 			n2args += 4;
 			n2 = realloc(n2, n2args * sizeof(char *));
 			if (!n2) {
-				SYSERROR("out of memory");
+				CSYSERROR(c, "out of memory");
 				exit(1);
 			}
 			// note n2[n2args-1] is NULL
@@ -1095,12 +1102,12 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
 		}
 		/* execute */
 		execvp(tpath, newargv);
-		SYSERROR("failed to execute template %s", tpath);
+		CSYSERROR(c, "failed to execute template %s", tpath);
 		exit(1);
 	}
 
 	if (wait_for_pid(pid) != 0) {
-		ERROR("container creation template for %s failed", c->name);
+		CERROR(c, "container creation template for %s failed", c->name);
 		return false;
 	}
 
@@ -2046,6 +2053,7 @@ out:
 static bool set_config_item_locked(struct lxc_container *c, const char *key, const char *v)
 {
 	struct lxc_config_t *config;
+	bool bret;
 
 	if (!c->lxc_conf)
 		c->lxc_conf = lxc_conf_init();
@@ -2054,7 +2062,10 @@ static bool set_config_item_locked(struct lxc_container *c, const char *key, con
 	config = lxc_getconfig(key);
 	if (!config)
 		return false;
-	return (0 == config->cb(key, v, c->lxc_conf));
+	bret = (0 == config->cb(key, v, c->lxc_conf));
+	if (!container_log_init(c))
+		ERROR("Failed to set the requested log settings");
+	return bret;
 }
 
 static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v)
@@ -3384,12 +3395,6 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
 	c->add_device_node = lxcapi_add_device_node;
 	c->remove_device_node = lxcapi_remove_device_node;
 
-	/* we'll allow the caller to update these later */
-	if (lxc_log_init(NULL, "none", NULL, "lxc_container", 0, c->config_path)) {
-		fprintf(stderr, "failed to open log\n");
-		goto err;
-	}
-
 	return c;
 
 err:
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index ba15ab7..a4982f8 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -740,6 +740,13 @@ struct lxc_container {
 	 * \return \c true on success, else \c false.
 	 */
 	bool (*remove_device_node)(struct lxc_container *c, const char *src_path, const char *dest_path);
+
+	/*
+	 * per-container log info
+	 * If this is unset, then global logging is used
+	 */
+	char *log_file;
+	struct lxc_log_category *log_category;
 };
 
 /*!
-- 
1.9.0



More information about the lxc-devel mailing list