common: added a simple logging implementation.
authorKrisztian Litkey <kli@iki.fi>
Fri, 6 Apr 2012 11:04:09 +0000 (14:04 +0300)
committerKrisztian Litkey <kli@iki.fi>
Fri, 6 Apr 2012 11:04:09 +0000 (14:04 +0300)
src/common/log.c [new file with mode: 0644]
src/common/log.h [new file with mode: 0644]

diff --git a/src/common/log.c b/src/common/log.c
new file mode 100644 (file)
index 0000000..bc14b02
--- /dev/null
@@ -0,0 +1,189 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <common/log.h>
+
+static int log_mask = MRP_LOG_MASK_ERROR;
+static const char *log_target = MRP_LOG_TO_STDERR;
+static FILE *log_fp;
+
+
+mrp_log_mask_t mrp_log_parse_levels(const char *levels)
+{
+    const char *p;
+    mrp_log_mask_t mask;
+    
+    mask = 0;
+    
+    if (levels == NULL) {
+        if (mask == 0)
+            mask = 1;
+        else {
+            mask <<= 1;
+            mask  |= 1;
+        }
+    }
+    else {
+        p = levels;
+        while (p && *p) {
+#           define MATCHES(s, l) (!strcmp(s, l) ||                      \
+                                  !strncmp(s, l",", sizeof(l",") - 1))
+            
+            if (MATCHES(p, "info"))
+                mask |= MRP_LOG_MASK_INFO;
+            else if (MATCHES(p, "error"))
+                mask |= MRP_LOG_MASK_ERROR;
+            else if (MATCHES(p, "warning"))
+                mask |= MRP_LOG_MASK_WARNING;
+            else
+               return -1;
+           
+            if ((p = strchr(p, ',')) != NULL)
+                p += 1;
+
+#           undef MATCHES
+        }
+    }
+
+    return mask;
+}
+
+
+const char *mrp_log_parse_target(const char *target)
+{
+    if (!strcmp(target, "stderr"))
+       return MRP_LOG_TO_STDERR;
+    if (!strcmp(target, "stdout"))
+       return MRP_LOG_TO_STDOUT;
+    if (!strcmp(target, "syslog"))
+       return MRP_LOG_TO_SYSLOG;
+    else
+       return target;
+}
+
+
+mrp_log_mask_t mrp_log_enable(mrp_log_mask_t enabled)
+{
+    mrp_log_mask_t old_mask = log_mask;
+
+    log_mask |= enabled;
+    
+    return old_mask;
+}
+
+
+mrp_log_mask_t mrp_log_disable(mrp_log_mask_t disabled)
+{
+    mrp_log_mask_t old_mask = log_mask;
+
+    log_mask &= ~disabled;
+    
+    return old_mask;
+}
+
+
+mrp_log_mask_t mrp_log_set_mask(mrp_log_mask_t enabled)
+{
+    mrp_log_mask_t old_mask = log_mask;
+
+    log_mask = enabled;
+    
+    return old_mask;
+}
+
+
+int mrp_log_set_target(const char *target)
+{
+    const char *old_target = log_target;
+    FILE       *old_fp     = log_fp;
+    
+    if (!target || log_target == target)
+       return FALSE;
+
+    if (target == MRP_LOG_TO_SYSLOG) {
+       log_target = target;
+       log_fp     = NULL;
+       openlog(NULL, 0, LOG_DAEMON);
+    }
+    else if (target == MRP_LOG_TO_STDERR) {
+       log_target = target;
+       log_fp     = stdout;
+    }
+    else if (target == MRP_LOG_TO_STDOUT) {
+       log_target = target;
+       log_fp     = stdout;
+    }
+    else {
+       log_target = target;
+       log_fp     = fopen(log_target, "a");
+       
+       if (log_fp == NULL) {
+           log_target = old_target;
+           log_fp     = old_fp;
+
+           return FALSE;
+       }
+    }
+
+    if (old_target == MRP_LOG_TO_SYSLOG)
+       closelog();
+    else if (old_target != MRP_LOG_TO_STDOUT && old_target != MRP_LOG_TO_STDERR)
+       fclose(old_fp);
+
+    return TRUE;
+}
+
+
+void mrp_log_msg(mrp_log_level_t level, const char *file,
+                int line, const char *func, const char *format, ...)
+{
+    va_list     ap;
+    int         lvl;
+    const char *prefix;
+    char        prfx[2*1024];
+    
+    (void)file;
+    (void)line;
+
+    if (!(log_mask & (1 << level)))
+       return;
+
+    switch (level) {
+    case MRP_LOG_ERROR:   lvl = LOG_ERR;     prefix = "E: "; break;
+    case MRP_LOG_WARNING: lvl = LOG_WARNING; prefix = "W: "; break;
+    case MRP_LOG_INFO:    lvl = LOG_INFO;    prefix = "I: "; break;
+    case MRP_LOG_DEBUG:   lvl = LOG_INFO;
+       snprintf(prfx, sizeof(prfx) - 1, "D: [%s] ", func);
+       prfx[sizeof(prfx)-1] = '\0';
+       prefix = prfx;
+       break;
+    default:
+       return;
+    }
+    
+    va_start(ap, format);
+
+    if (log_fp == NULL)
+       vsyslog(lvl, format, ap);
+    else {
+       fputs(prefix, log_fp);
+       vfprintf(log_fp, format, ap); fputs("\n", log_fp);
+       fflush(log_fp);
+    }
+
+    va_end(ap);
+}
+
+
+/*
+ * workaround for not being able to initialize log_fp to stderr
+ */
+
+static __attribute__((constructor)) void set_default_logging(void)
+{
+    log_target = MRP_LOG_TO_STDERR;
+    log_fp     = stderr;
+}
diff --git a/src/common/log.h b/src/common/log.h
new file mode 100644 (file)
index 0000000..b03e75a
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef __MURPHY_LOG_H__
+#define __MURPHY_LOG_H__
+
+/** \file
+ * Logging functions and macros.
+ */
+
+#include <syslog.h>
+
+#include <common/macros.h>
+
+MRP_CDECL_BEGIN
+
+#define MRP_LOG_NAME_ERROR   "error"             /**< name for error level */
+#define MRP_LOG_NAME_WARNING "warning"           /**< name for warning level */
+#define MRP_LOG_NAME_INFO    "info"              /**< name for info level */
+#define MRP_LOG_NAME_DEBUG   "debug"             /**< name for debug level */
+
+
+/**
+ * Logging levels.
+ */
+typedef enum {
+    MRP_LOG_ERROR = 0,                           /**< error log level */
+    MRP_LOG_WARNING,                             /**< warning log level */
+    MRP_LOG_INFO,                                /**< info log level  */
+    MRP_LOG_DEBUG,                               /**< debug log level */
+} mrp_log_level_t;
+
+
+/**
+ * Logging masks.
+ */
+typedef enum {
+    MRP_LOG_MASK_ERROR   = 0x01,                 /**< error logging mask */
+    MRP_LOG_MASK_WARNING = 0x02,                 /**< warning logging mask */
+    MRP_LOG_MASK_INFO    = 0x04,                 /**< info logging mask */
+    MRP_LOG_MASK_DEBUG   = 0x08,                 /**< debug logging mask */
+} mrp_log_mask_t;
+
+#define MRP_LOG_MASK(level) (1 << ((level) - 1)) /**< mask of level */
+#define MRP_LOG_UPTO(level) ((1 << (level)) - 1) /**< mask up to level */
+
+/** Parse a string of comma-separated log level names to a log mask. */
+mrp_log_mask_t mrp_log_parse_levels(const char *levels);
+
+/** Clear current logging level and enable levels in mask. */
+mrp_log_mask_t mrp_log_set_mask(mrp_log_mask_t mask);
+
+/** Enable logging for levels in mask. */
+mrp_log_mask_t mrp_log_enable(mrp_log_mask_t mask);
+
+/** Disable logging for levels in mask. */
+mrp_log_mask_t mrp_log_disable(mrp_log_mask_t mask);
+
+/**
+ * Logging target names.
+ */
+#define MRP_LOG_NAME_STDOUT  "stdout"
+#define MRP_LOG_NAME_STDERR  "stderr"
+#define MRP_LOG_NAME_SYSLOG  "syslog"
+
+/**
+ * Logging targets.
+ */
+#define MRP_LOG_TO_STDOUT     ((const char *)1)
+#define MRP_LOG_TO_STDERR     ((const char *)2)
+#define MRP_LOG_TO_SYSLOG     ((const char *)3)
+#define MRP_LOG_TO_FILE(path) ((const char *)(path))
+
+/** Parse a log target name to MRP_LOG_TO_*. */
+const char *mrp_log_parse_target(const char *target);
+
+/** Set logging target. */
+int mrp_log_set_target(const char *target);
+
+/** Log an error. */
+#define mrp_log_error(fmt, args...) \
+    mrp_log_msg(MRP_LOG_ERROR, __LOC__, fmt , ## args)
+
+/** Log a warning. */
+#define mrp_log_warning(fmt, args...) \
+    mrp_log_msg(MRP_LOG_WARNING, __LOC__, fmt , ## args)
+
+/** Log an informational message. */
+#define mrp_log_info(fmt, args...) \
+    mrp_log_msg(MRP_LOG_INFO, __LOC__, fmt , ## args)
+
+/** Log an (unclassified) debugging message. */
+#define mrp_debug(fmt, args...) \
+    mrp_log_msg(MRP_LOG_DEBUG, __LOC__, fmt , ## args)
+
+/** Generic logging function. */
+void mrp_log_msg(mrp_log_level_t level,
+                const char *file, int line, const char *func,
+                const char *format, ...) MRP_PRINTF_LIKE(5, 6);
+
+MRP_CDECL_END
+
+#endif /* __MURPHY_LOG_H__ */