]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
lxc: introduce log4c style logging
authorCedric Le Goater <legoater@free.fr>
Tue, 21 Apr 2009 19:51:13 +0000 (21:51 +0200)
committerDaniel Lezcano <dlezcano@fr.ibm.com>
Tue, 21 Apr 2009 19:51:13 +0000 (21:51 +0200)
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
src/lxc/log.h

index d95c4b8cc668a04de016a00640f900770db5f7c5..676e5d3e7f04caa8451e7a04db791db3eb856833 100644 (file)
@@ -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)"
-
index 620e10c359def6bf0d6470a49fe167841e3d8121..39005b46ab41557d0fae7ea55291b9df68920170 100644 (file)
@@ -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__); \