From: Cedric Le Goater <legoater@free.fr>

lxc_log_init() should be called in each main() of a command
to define the default log priority and log file.

Signed-off-by: Cedric Le Goater <legoater@free.fr>
Acked-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 src/lxc/log.c |  130 ++++++++++++++++++++++++++++++
 src/lxc/log.h |  244 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 371 insertions(+), 3 deletions(-)

Index: lxc/src/lxc/log.h
===================================================================
--- lxc.orig/src/lxc/log.h
+++ lxc/src/lxc/log.h
@@ -1,6 +1,250 @@
 #ifndef _log_h
 #define _log_h

+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <string.h>
+
+/* predefined priorities. */
+enum {
+	LXC_LOG_PRIORITY_TRACE,
+	LXC_LOG_PRIORITY_DEBUG,
+	LXC_LOG_PRIORITY_INFO,
+	LXC_LOG_PRIORITY_NOTICE,
+	LXC_LOG_PRIORITY_WARN,
+	LXC_LOG_PRIORITY_ERROR,
+	LXC_LOG_PRIORITY_CRIT,
+	LXC_LOG_PRIORITY_ALERT,
+	LXC_LOG_PRIORITY_FATAL,
+	LXC_LOG_PRIORITY_NOTSET,
+};
+
+/* location information of the logging event */
+struct lxc_log_locinfo {
+	const char	*file;
+	const char	*func;
+	int		line;
+};
+
+#define LXC_LOG_LOCINFO_INIT						\
+	{ .file = __FILE__, .func = __func__, .line = __LINE__	}
+
+/* brief logging event object */
+struct lxc_log_event {
+	const char*		category;
+	int			priority;
+	struct timeval		timestamp;
+	struct lxc_log_locinfo	*locinfo;
+	const char		*fmt;
+	va_list 		va;
+};
+
+/* log appender object */
+struct lxc_log_appender {
+	const char*	name;
+	int (*append)(const struct lxc_log_appender *,
+		      const struct lxc_log_event *);
+
+	/*
+	 * appenders can be stacked
+	 */
+	struct lxc_log_appender	*next;
+};
+
+/* log category object */
+struct lxc_log_category {
+	const char			*name;
+	int				priority;
+	struct lxc_log_appender		*appender;
+	const struct lxc_log_category	*parent;
+};
+
+/*
+ * Returns true if the chained priority is equal to or higher than
+ * given priority.
+ */
+static inline int
+lxc_log_priority_is_enabled(const struct lxc_log_category* category,
+			   int priority)
+{
+	while (category->priority == LXC_LOG_PRIORITY_NOTSET &&
+	       category->parent)
+		category = category->parent;
+
+	return priority >= category->priority;
+}
+
+/*
+ * converts a priority to a literal string
+ */
+static inline const char* lxc_log_priority_to_string(int priority)
+{
+	switch (priority) {
+	case LXC_LOG_PRIORITY_TRACE:	return "TRACE";
+	case LXC_LOG_PRIORITY_DEBUG:	return "DEBUG";
+	case LXC_LOG_PRIORITY_INFO:	return "INFO";
+	case LXC_LOG_PRIORITY_NOTICE:	return "NOTICE";
+	case LXC_LOG_PRIORITY_WARN:	return "WARN";
+	case LXC_LOG_PRIORITY_ERROR:	return "ERROR";
+	case LXC_LOG_PRIORITY_CRIT:	return "CRIT";
+	case LXC_LOG_PRIORITY_ALERT:	return "ALERT";
+	case LXC_LOG_PRIORITY_FATAL:	return "FATAL";
+	default:
+		return "NOTSET";
+	}
+}
+/*
+ * converts a literal priority to an int
+ */
+static inline int lxc_log_priority_to_int(const char* name)
+{
+	if (!strcasecmp("TRACE",  name)) return LXC_LOG_PRIORITY_TRACE;
+	if (!strcasecmp("DEBUG",  name)) return LXC_LOG_PRIORITY_DEBUG;
+	if (!strcasecmp("INFO",   name)) return LXC_LOG_PRIORITY_INFO;
+	if (!strcasecmp("NOTICE", name)) return LXC_LOG_PRIORITY_NOTICE;
+	if (!strcasecmp("WARN",   name)) return LXC_LOG_PRIORITY_WARN;
+	if (!strcasecmp("ERROR",  name)) return LXC_LOG_PRIORITY_ERROR;
+	if (!strcasecmp("CRIT",   name)) return LXC_LOG_PRIORITY_CRIT;
+	if (!strcasecmp("ALERT",  name)) return LXC_LOG_PRIORITY_ALERT;
+	if (!strcasecmp("FATAL",  name)) return LXC_LOG_PRIORITY_FATAL;
+
+	return LXC_LOG_PRIORITY_NOTSET;
+}
+
+static inline void
+__lxc_log_append(const struct lxc_log_appender *appender,
+		const struct lxc_log_event* event)
+{
+	while (appender) {
+		appender->append(appender, event);
+		appender = appender->next;
+	}
+}
+
+static inline void
+__lxc_log(const struct lxc_log_category* category,
+	 const struct lxc_log_event* event)
+{
+	while (category) {
+		__lxc_log_append(category->appender, event);
+		category = category->parent;
+	}
+}
+
+/*
+ * Helper macro to define log fonctions.
+ */
+#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_log_locinfo* locinfo,	\
+				  const char* format, ...)		\
+{									\
+	if (lxc_log_priority_is_enabled(acategory, 			\
+					LXC_LOG_PRIORITY_##PRIORITY)) {	\
+		struct lxc_log_event evt = {				\
+			.category	= (acategory)->name,		\
+			.priority	= LXC_LOG_PRIORITY_##PRIORITY,	\
+			.fmt		= format,			\
+			.locinfo	= locinfo			\
+		};							\
+									\
+		gettimeofday(&evt.timestamp, NULL);			\
+									\
+		va_start(evt.va, format);				\
+		__lxc_log(acategory, &evt);				\
+		va_end(evt.va);						\
+	}								\
+}
+
+/*
+ * Helper macro to define and use static categories.
+ */
+#define lxc_log_category_define(name, parent)				\
+	extern struct lxc_log_category lxc_log_category_##parent;	\
+	struct lxc_log_category lxc_log_category_##name = {		\
+		#name,							\
+		LXC_LOG_PRIORITY_NOTSET,				\
+		NULL,							\
+		&lxc_log_category_##parent				\
+	};
+
+#define lxc_log_define(name, parent)					\
+	lxc_log_category_define(name, parent)				\
+									\
+	lxc_log_priority_define(&lxc_log_category_##name, TRACE)	\
+	lxc_log_priority_define(&lxc_log_category_##name, DEBUG)	\
+	lxc_log_priority_define(&lxc_log_category_##name, INFO)		\
+	lxc_log_priority_define(&lxc_log_category_##name, NOTICE)	\
+	lxc_log_priority_define(&lxc_log_category_##name, WARN)		\
+	lxc_log_priority_define(&lxc_log_category_##name, ERROR)	\
+	lxc_log_priority_define(&lxc_log_category_##name, CRIT)		\
+	lxc_log_priority_define(&lxc_log_category_##name, ALERT)	\
+	lxc_log_priority_define(&lxc_log_category_##name, FATAL)
+
+#define lxc_log_category_priority(name) 				\
+	(lxc_log_priority_to_string(lxc_log_category_##name.priority))
+
+/*
+ * top categories
+ */
+extern struct lxc_log_category lxc_log_category_lxc;
+
+#define TRACE(format, ...) do {						\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_TRACE(&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__);			\
+} while (0)
+
+#define INFO(format, ...) do {						\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_INFO(&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__);			\
+} while (0)
+
+#define WARN(format, ...) do {						\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_WARN(&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__);			\
+} while (0)
+
+#define CRIT(format, ...) do {						\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_CRIT(&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__);			\
+} while (0)
+
+#define FATAL(format, ...) do {						\
+	struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT;		\
+	LXC_FATAL(&locinfo, format, ##__VA_ARGS__);			\
+} while (0)
+
+
+
+#define SYSERROR(format, ...) do {				    	\
+	ERROR("%s - " format "\n", strerror(errno), ##__VA_ARGS__); 	\
+} while (0)
+
+
 #define lxc_log(format, level, ...) do {			       \
 		fprintf(stderr, "[%s] \t%s:%d - " format "\n", \
 			level, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
Index: lxc/src/lxc/log.c
===================================================================
--- lxc.orig/src/lxc/log.c
+++ lxc/src/lxc/log.c
@@ -1,9 +1,133 @@
 #include <stdio.h>
 #include <errno.h>
-#include <stdarg.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#define __USE_GNU /* for *_CLOEXEC */
+
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <lxc/log.h>
+
+#define LXC_LOG_PREFIX_SIZE	32
+#define LXC_LOG_BUFFER_SIZE	512
+
+int lxc_log_fd = 2;
+
+static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
+
+lxc_log_define(lxc_log, lxc);
+
+/*---------------------------------------------------------------------------*/
+static int log_append_logfile(const struct lxc_log_appender *appender,
+	const struct lxc_log_event *event)
+{
+	char buffer[LXC_LOG_BUFFER_SIZE];
+	int n;
+
+	if (lxc_log_fd == -1)
+		return 0;
+
+	n = snprintf(buffer, sizeof(buffer),
+		     "%15s %10ld.%03ld %-8s %s - ",
+		     log_prefix,
+		     event->timestamp.tv_sec,
+		     event->timestamp.tv_usec / 1000,
+		     lxc_log_priority_to_string(event->priority),
+		     event->category);
+
+	n += vsnprintf(buffer + n, sizeof(buffer) - n, event->fmt,
+		       event->va);
+
+	if (n >= sizeof(buffer) - 1) {
+		WARN("truncated next event from %d to %d bytes", n,
+		     sizeof(buffer));
+		n = sizeof(buffer) - 1;
+	}
+
+	buffer[n] = '\n';
+
+	return write(lxc_log_fd, buffer, n + 1);
+}
+
+static struct lxc_log_appender 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,
+};
+
+struct lxc_log_category lxc_log_category_lxc = {
+	.name		= "lxc",
+	.priority	= LXC_LOG_PRIORITY_ERROR,
+	.appender	= &log_appender_logfile,
+	.parent		= &log_root
+};
+
+/*---------------------------------------------------------------------------*/
+extern void lxc_log_setprefix(const char *prefix)
+{
+	strncpy(log_prefix, prefix, sizeof(log_prefix));
+	log_prefix[sizeof(log_prefix) - 1] = 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static int log_open(const char *name)
+{
+	int fd;
+	int newfd;
+
+	fd = open(name, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0666);
+	if (fd == -1) {
+		ERROR("failed to open log file \"%s\" : %s", name,
+		      strerror(errno));
+		return -1;
+	}
+
+	if (fd > 2)
+		return fd;
+
+	newfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+	if (newfd == -1)
+		ERROR("failed to dup log fd %d : %s", fd, strerror(errno));
+
+	close(fd);
+	return newfd;
+}
+
+/*---------------------------------------------------------------------------*/
+extern int lxc_log_init(const char *file, int priority, const char *prefix)
+{
+	lxc_log_category_lxc.priority = priority;
+
+	if (prefix)
+		lxc_log_setprefix(prefix);
+
+	if (file) {
+		int fd;
+
+		fd = log_open(file);
+		if (fd == -1) {
+			ERROR("failed to initialize log service");
+			return -1;
+		}
+
+		lxc_log_fd = fd;
+	}
+
+	return 0;
+}

-#include <log.h>

 #define MAXTIMELEN 47;
 #define ERRNO_FORMAT "%d (%s)"
-






