Code

utils error: Added module for error reporting.
authorSebastian Harl <sh@tokkee.org>
Sun, 10 Mar 2013 19:24:41 +0000 (20:24 +0100)
committerSebastian Harl <sh@tokkee.org>
Sun, 10 Mar 2013 19:24:41 +0000 (20:24 +0100)
This module will transparently store error information for each thread (similar
to errno). Support functions to store and retrieve error messages are available
on top of that. Once the error message has been passed to SysDB, it will log
the entire message. Currently, only printing to the standard error channel are
available.

src/Makefile.am
src/include/utils/error.h [new file with mode: 0644]
src/utils/error.c [new file with mode: 0644]

index b75bfff7707df6baf99c1d0e22e6cfd5f06a496b..9de8dd02b966108990b20f76f25785039870236c 100644 (file)
@@ -24,6 +24,7 @@ libsysdb_la_SOURCES = \
                core/plugin.c include/core/plugin.h \
                core/store.c include/core/store.h \
                include/utils/data.h \
                core/plugin.c include/core/plugin.h \
                core/store.c include/core/store.h \
                include/utils/data.h \
+               utils/error.c include/utils/error.h \
                utils/llist.c include/utils/llist.h \
                utils/string.c include/utils/string.h \
                utils/time.c include/utils/time.h \
                utils/llist.c include/utils/llist.h \
                utils/string.c include/utils/string.h \
                utils/time.c include/utils/time.h \
diff --git a/src/include/utils/error.h b/src/include/utils/error.h
new file mode 100644 (file)
index 0000000..8b2a177
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * SysDB - src/include/utils/error.h
+ * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * SysDB error handling:
+ * Error handling in SysDB is done on a by-thread basis, that is, each thread
+ * will use its own memory region to store information about the last reported
+ * error.
+ * Once the error message has been passed to SysDB, it will log the entire
+ * message at once. XXX: currently, SysDB only supports printing the error to
+ * the standard error channel; support for other logging backends will be
+ * added later in a modular fashion.
+ */
+
+#ifndef SDB_UTILS_ERROR_H
+#define SDB_UTILS_ERROR_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* max length of any error message */
+#ifndef SDB_MAX_ERROR
+#      define SDB_MAX_ERROR 4096
+#endif /* ! SDB_MAX_ERROR */
+
+/* On Linux systems and possibly others, this should be the same as the LOG_
+ * constants defined by syslog. */
+enum {
+       SDB_LOG_EMERG   = 0,
+       SDB_LOG_ERR     = 3,
+       SDB_LOG_WARNING = 4,
+       SDB_LOG_NOTICE  = 5,
+       SDB_LOG_INFO    = 6,
+       SDB_LOG_DEBUG   = 7,
+};
+#define SDB_LOG_PRIO_TO_STRING(prio) \
+       (((prio) == SDB_LOG_EMERG) ? "EMERG" \
+               : ((prio) == SDB_LOG_ERR) ? "ERR" \
+               : ((prio) == SDB_LOG_WARNING) ? "WARNING" \
+               : ((prio) == SDB_LOG_NOTICE) ? "NOTICE" \
+               : ((prio) == SDB_LOG_INFO) ? "INFO" \
+               : ((prio) == SDB_LOG_DEBUG) ? "DEBUG" : "UNKNOWN")
+
+/*
+ * sdb_error_set:
+ * Set the current error message. The string will be formated in printf-style
+ * using the specified format and arguments and logged with the specified
+ * priority. XXX: SDB_LOG_EMERG might, at some point and/or depending on
+ * configuration, try a clean shut-down of the process.
+ */
+int
+sdb_error_set(int prio, const char *fmt, ...);
+
+/*
+ * sdb_error_start, sdb_error_append, sdb_error_end:
+ * Compose the current error message from multiple parts. The error message
+ * will only be logged after calling sdb_error_finish().
+ * See sdb_error_set for details.
+ */
+int
+sdb_error_start(int prio, const char *fmt, ...);
+int
+sdb_error_append(const char *fmt, ...);
+int
+sdb_error_finish(void);
+
+/*
+ * sdb_error_get:
+ * Get the current error message. The string returned by this function is
+ * owned by SysDB and might point to static memory -- do not modify or free
+ * it.
+ */
+const char *
+sdb_error_get(void);
+
+/*
+ * sdb_error_get_prio:
+ * Get the priority of the current error message -- see the SDB_LOG_ constants
+ * for details.
+ */
+int
+sdb_error_get_prio(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ! SDB_UTILS_ERROR_H */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/utils/error.c b/src/utils/error.c
new file mode 100644 (file)
index 0000000..34213b3
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * SysDB - src/utils/error.c
+ * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "utils/error.h"
+
+#include <pthread.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * private data types
+ */
+
+typedef struct {
+       int   prio;
+       char  msg[SDB_MAX_ERROR];
+       _Bool finalized;
+} sdb_error_ctx_t;
+#define SDB_ERROR_INIT { -1, "", 1 }
+
+/*
+ * private variables
+ */
+
+static sdb_error_ctx_t default_error_ctx = SDB_ERROR_INIT;
+
+static pthread_key_t error_ctx_key;
+static _Bool         error_ctx_key_initialized = 0;
+
+/*
+ * private helper functions
+ */
+
+static void
+sdb_error_ctx_init(void)
+{
+       if (error_ctx_key_initialized)
+               return;
+
+       pthread_key_create(&error_ctx_key, NULL);
+       error_ctx_key_initialized = 1;
+} /* sdb_error_init */
+
+static sdb_error_ctx_t *
+sdb_error_ctx_create(void)
+{
+       sdb_error_ctx_t *ctx;
+
+       ctx = malloc(sizeof(*ctx));
+       if (! ctx)
+               return NULL;
+
+       *ctx = default_error_ctx;
+
+       if (! error_ctx_key_initialized)
+               sdb_error_ctx_init();
+       pthread_setspecific(error_ctx_key, ctx);
+       return ctx;
+} /* sdb_error_ctx_create */
+
+static sdb_error_ctx_t *
+sdb_error_get_ctx(void)
+{
+       sdb_error_ctx_t *ctx;
+
+       if (! error_ctx_key_initialized)
+               sdb_error_ctx_init();
+       ctx = pthread_getspecific(error_ctx_key);
+
+       if (! ctx)
+               ctx = sdb_error_ctx_create();
+       if (! ctx)
+               return NULL;
+       return ctx;
+} /* sdb_error_get_ctx */
+
+static int
+sdb_error_clear(void)
+{
+       sdb_error_ctx_t *ctx;
+
+       ctx = sdb_error_get_ctx();
+       if (! ctx)
+               return -1;
+
+       ctx->prio = -1;
+       ctx->msg[0] = '\0';
+       ctx->finalized = 1;
+       return 0;
+} /* sdb_error_clear */
+
+static int
+sdb_error_vappend(int prio, const char *fmt, va_list ap)
+{
+       sdb_error_ctx_t *ctx;
+       size_t len;
+
+       ctx = sdb_error_get_ctx();
+       if (! ctx)
+               return -1;
+
+       len = strlen(ctx->msg);
+       if (len >= sizeof(ctx->msg))
+               return 0; /* nothing written */
+
+       if (prio >= 0)
+               ctx->prio = prio;
+
+       ctx->finalized = 0;
+       return vsnprintf(ctx->msg + len, sizeof(ctx->msg) - len, fmt, ap);
+} /* sdb_error_vappend */
+
+static int
+sdb_error_log(void)
+{
+       sdb_error_ctx_t *ctx;
+       int ret;
+
+       ctx = sdb_error_get_ctx();
+       if (! ctx)
+               return -1;
+
+       if (ctx->finalized)
+               return 0;
+
+       ret = fprintf(stderr, "[%s] %s\n",
+                       SDB_LOG_PRIO_TO_STRING(ctx->prio), ctx->msg);
+       ctx->finalized = 1;
+       return ret;
+} /* sdb_error_log */
+
+/*
+ * public API
+ */
+
+int
+sdb_error_set(int prio, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       if (sdb_error_clear())
+               return -1;
+
+       va_start(ap, fmt);
+       ret = sdb_error_vappend(prio, fmt, ap);
+       va_end(ap);
+
+       sdb_error_log();
+       return ret;
+} /* sdb_error_set */
+
+int
+sdb_error_start(int prio, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       if (sdb_error_clear())
+               return -1;
+
+       va_start(ap, fmt);
+       ret = sdb_error_vappend(prio, fmt, ap);
+       va_end(ap);
+
+       return ret;
+} /* sdb_error_start */
+
+int
+sdb_error_append(const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, fmt);
+       ret = sdb_error_vappend(/* dont change prio */ -1, fmt, ap);
+       va_end(ap);
+
+       return ret;
+} /* sdb_error_append */
+
+int
+sdb_error_finish(void)
+{
+       return sdb_error_log();
+} /* sdb_error_finish */
+
+const char *
+sdb_error_get(void)
+{
+       sdb_error_ctx_t *ctx;
+
+       ctx = sdb_error_get_ctx();
+       if (! ctx)
+               return "success";
+       return ctx->msg;
+} /* sdb_error_get */
+
+int
+sdb_error_get_prio(void)
+{
+       sdb_error_ctx_t *ctx;
+
+       ctx = sdb_error_get_ctx();
+       if (! ctx)
+               return -1;
+       return ctx->prio;
+} /* sdb_error_get_prio */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+