add logwatch module, that can already open FIFOs
authorTero Marttila <terom@fixme.fi>
Tue, 07 Apr 2009 21:09:25 +0300
changeset 119 64f50072db9e
parent 118 05b8d5150313
child 120 576bab0a1c5a
add logwatch module, that can already open FIFOs
src/CMakeLists.txt
src/module.c
src/module.h
src/modules/logwatch.c
src/modules/logwatch.h
src/modules/logwatch_source.c
--- a/src/CMakeLists.txt	Tue Apr 07 19:41:48 2009 +0300
+++ b/src/CMakeLists.txt	Tue Apr 07 21:09:25 2009 +0300
@@ -18,6 +18,7 @@
 set (NEXUS_SOURCES nexus.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES} ${LUA_SOURCES} ${CONSOLE_SOURCES} signals.c module.c config.c)
 set (TEST_SOURCES test.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES})
 set (IRC_LOG_SOURCES modules/irc_log.c)
+set (LOGWATCH_SOURCES modules/logwatch.c modules/logwatch_source.c)
 
 # define our libraries
 set (MODULE_LIBRARIES "dl")
@@ -32,6 +33,7 @@
 
 # add our modules
 add_library (irc_log MODULE ${IRC_LOG_SOURCES})
+add_library (logwatch MODULE ${LOGWATCH_SOURCES})
 
 # set libraries
 target_link_libraries (nexus ${NEXUS_LIBRARIES})
@@ -39,7 +41,7 @@
 target_link_libraries (irc_log ${Evsql_LIBRARIES})
 
 # global target properties
-set_target_properties (nexus test irc_log PROPERTIES
+set_target_properties (nexus test irc_log logwatch PROPERTIES
     COMPILE_FLAGS   ${CFLAGS}
 )
 
@@ -49,7 +51,7 @@
 )
 
 # modules have weird names
-set_target_properties (irc_log PROPERTIES
+set_target_properties (irc_log logwatch PROPERTIES
     PREFIX                      "mod_"
     LIBRARY_OUTPUT_DIRECTORY    "modules"
 )
--- a/src/module.c	Tue Apr 07 19:41:48 2009 +0300
+++ b/src/module.c	Tue Apr 07 21:09:25 2009 +0300
@@ -316,15 +316,21 @@
     // update status
     module->unloading = true;
 
-    // invoke the unload func, passing it our reference
-    // note that the module might not exist anymore after calling this
-    if ((err = module->desc->unload(module->ctx, module))) {
-        // mark it as "unloaded"
+    if (module->desc->unload) {
+        // invoke the unload func, passing it our reference
+        // note that the module might not exist anymore after calling this
+        if ((err = module->desc->unload(module->ctx, module))) {
+            // mark it as "unloaded"
+            module_unloaded(module);
+
+            return err;
+        }
+
+    } else {
+        // no unload procedure, just destroy it as soon as needed
         module_unloaded(module);
 
-        return err;
     }
-
     // ok
     return SUCCESS;
 }
@@ -371,7 +377,7 @@
         TAILQ_REMOVE(&module->modules->list, module, modules_list);
 
     // run the destroy hook
-    if (module->desc && module->desc->destroy)
+    if (module->desc && module->desc->destroy && module->ctx)
         module->desc->destroy(module->ctx);
 
     // unload the dl handle
--- a/src/module.h	Tue Apr 07 19:41:48 2009 +0300
+++ b/src/module.h	Tue Apr 07 21:09:25 2009 +0300
@@ -88,7 +88,7 @@
      * If the unload operation fails (returns an error code), then the module is considered as unloaded (as if
      * module_unloaded() was called - don't call this if you return an error).
      *
-     * Implementing this is mandatory.
+     * Implementing this is optional, if all of this can be implemented in destroy.
      *
      * @param ctx the module's context pointer as returned by init
      * @param module the hanging module reference, that must be passed to module_unloaded()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/logwatch.c	Tue Apr 07 21:09:25 2009 +0300
@@ -0,0 +1,84 @@
+#include "logwatch.h"
+
+#include "../config.h"
+
+static err_t logwatch_init (struct nexus *nexus, void **ctx_ptr, struct error_info *err)
+{
+    struct logwatch *ctx;
+
+    // allocate
+    if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+        RETURN_SET_ERROR(err, ERR_CALLOC);
+    
+    // init
+    TAILQ_INIT(&ctx->sources);
+    TAILQ_INIT(&ctx->filters);
+    TAILQ_INIT(&ctx->channels);
+
+    // store
+    ctx->nexus = nexus;
+
+    // ok
+    *ctx_ptr = ctx;
+
+    return SUCCESS;
+}
+
+/**
+ * Add a logwatch_source with a FIFO at the given path
+ */
+static err_t logwatch_conf_source_fifo (void *_ctx, char *path, struct error_info *err)
+{
+    struct logwatch *ctx = _ctx;
+    
+    // open it
+    if (logwatch_open_fifo(ctx, path, err) == NULL)
+       return ERROR_CODE(err);
+
+    // ok
+    return SUCCESS;
+}
+
+/**
+ * Configuration options
+ */
+struct config_option logwatch_config_options[] = {
+    CONFIG_OPT_STRING(      "source_fifo",  &logwatch_conf_source_fifo, "<path>",           "read lines from the fifo at the given path"    ),
+
+    CONFIG_OPT_END
+};
+
+/**
+ * Deinitialize by freeing all filters, closing all sources, and releasing all channels.
+ *
+ * XXX: unused
+ */
+static err_t logwatch_unload (void *_ctx, struct module *module)
+{
+    struct logwatch *ctx = _ctx;
+
+    // XXX: implement
+
+    return SUCCESS;
+}
+
+static void logwatch_destroy (void *_ctx)
+{
+    struct logwatch *ctx = _ctx;
+    struct logwatch_source *source;
+
+    // flush the sources list
+    while ((source = TAILQ_FIRST(&ctx->sources)))
+        logwatch_source_destroy(source);
+}
+
+/**
+ * The module function table
+ */
+struct module_desc logwatch_module = {
+    .init               = logwatch_init,
+    .config_options     = logwatch_config_options,
+    .unload             = NULL, // logwatch_unload,
+    .destroy            = logwatch_destroy
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/logwatch.h	Tue Apr 07 21:09:25 2009 +0300
@@ -0,0 +1,113 @@
+/**
+ * @file
+ *
+ * A module to filter out certain lines from normal syslog() files, and forward them to an IRC channel.
+ */
+#include <sys/queue.h>
+#include "../irc_chan.h"
+#include "../sock.h"
+#include "../line_proto.h"
+
+#include <event2/event.h>
+#include <pcre.h>
+
+/**
+ * A source of log lines.
+ *
+ * XXX: currently this is just hardcoded to be a FIFO
+ */
+struct logwatch_source {
+    /** The logwatch context */
+    struct logwatch *ctx;
+
+    /** The input FIFO */
+    struct line_proto *lp;
+
+    /** Our entry in logwatch::sources */
+    TAILQ_ENTRY(logwatch_source) logwatch_sources;
+};
+
+/**
+ * Maximum length of input lines
+ */
+#define LOGWATCH_SOURCE_LINE_MAX 1024
+
+/**
+ * A filter specifies what lines to match, and how to then format the output.
+ */
+struct logwatch_filter {
+    /** The name of the filter */
+    char *name;
+
+    /** The source to restrict this to, if any */
+    const struct logwatch_sourcee *source;
+
+    /** The compiled regular expression to match */
+    pcre *regexp;
+
+    /** The output format string */
+    char *format;
+
+    /** The channel to send output to */
+    struct logwatch_chan *chan;
+
+    /** Our entry in logwatch::filters */
+    TAILQ_ENTRY(logwatch_filter) logwatch_filters;
+};
+
+/**
+ * A channel for outputting logwatch output
+ */
+struct logwatch_chan {
+    /** The channel... */
+    struct irc_chan *chan;
+
+    /** Our entry in logwatch::channels */
+    TAILQ_ENTRY(logwatch_chan) logwatch_channels;
+};
+
+/**
+ * The logwatch module state
+ */
+struct logwatch {
+    /** The nexus we are loaded on */
+    struct nexus *nexus;
+
+    /** List of sources */
+    TAILQ_HEAD(logwatch_source_list, logwatch_source) sources;
+
+    /** List of filters */
+    TAILQ_HEAD(logwatch_filter_list, logwatch_filter) filters;
+
+    /** List of output channels */
+    TAILQ_HEAD(logwatch_chan_list, logwatch_chan) channels;
+};
+
+/**
+ * Add a new FIFO logwatch_source
+ *
+ * @param ctx the logwatch state
+ * @param path the path to the fifo
+ * @param err returned error info
+ * @return the new logwatch_source, or NULL on error
+ */
+struct logwatch_source* logwatch_open_fifo (struct logwatch *ctx, const char *path, struct error_info *err);
+
+/**
+ * Destroy a source, removing it from the list of sources.
+ *
+ * XXX: remove all affected filters as well?
+ */
+void logwatch_source_destroy (struct logwatch_source *source);
+
+/**
+ * Add a new output channel
+ */
+struct logwatch_chan* logwatch_add_chan (struct logwatch *ctx, struct irc_chan *chan);
+
+/**
+ * Add a new filter
+ */
+struct logwatch_filter logwatch_add_filter (struct logwatch *ctx, const struct logwatch_source *source,
+        const char *regexp, const char *fmt, struct logwatch_chan *chan);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/logwatch_source.c	Tue Apr 07 21:09:25 2009 +0300
@@ -0,0 +1,87 @@
+#include "logwatch.h"
+#include "../log.h"
+
+#include <stdlib.h>
+
+void logwatch_source_on_line (char *line, void *arg)
+{
+    struct logwatch_source *source = arg;
+
+    log_info("%s", line);
+}
+
+void logwatch_source_on_error (struct error_info *err, void *arg)
+{
+    struct logwatch_source *source = arg;
+    
+    log_error("%s", error_msg(err));
+}
+
+static const struct line_proto_callbacks lp_callbacks = {
+    .on_line    = logwatch_source_on_line,
+    .on_error   = logwatch_source_on_error,
+};
+
+/**
+ * Initialize with the given sock
+ */
+err_t logwatch_source_init (struct logwatch_source *source, struct logwatch *ctx, struct sock_stream *stream, struct error_info *err)
+{
+    source->ctx = ctx;
+    
+    // create the lp to wrap the sock
+    if (line_proto_create(&source->lp, stream, LOGWATCH_SOURCE_LINE_MAX, &lp_callbacks, source, err))
+        goto error;
+
+    // add to logwatch_sources
+    TAILQ_INSERT_TAIL(&ctx->sources, source, logwatch_sources);
+    
+    // ok
+    return SUCCESS;
+
+error:    
+    return ERROR_CODE(err);
+}
+
+struct logwatch_source* logwatch_open_fifo (struct logwatch *ctx, const char *path, struct error_info *err)
+{
+    struct logwatch_source *source;
+    struct sock_stream *stream = NULL;
+
+    // alloc
+    if ((source = calloc(1, sizeof(*source))) == NULL)
+        JUMP_SET_ERROR(err, ERR_CALLOC);
+    
+    // open
+    if (fifo_open_read(&stream, path, err))
+        goto error;
+        
+    // init
+    if (logwatch_source_init(source, ctx, stream, err))
+        goto error;
+
+    // ok
+    return source;
+
+error:    
+    // cleanup
+    if (stream)
+        sock_stream_release(stream);
+    
+    if (source)
+        free(source);
+
+    return NULL;
+}
+
+void logwatch_source_destroy (struct logwatch_source *source)
+{
+    // release the line_proto
+    if (source->lp)
+        line_proto_release(source->lp);
+        
+    // remove from the list
+    TAILQ_REMOVE(&source->ctx->sources, source, logwatch_sources);
+
+    free(source);
+}