src/modules/logwatch.c
author Tero Marttila <terom@fixme.fi>
Sun, 12 Apr 2009 18:35:16 +0300
changeset 134 978041c1c04d
parent 133 e2d0c0c23b39
child 135 9159bd51525f
permissions -rw-r--r--
update TODO, partially update error.c, rename module_get to modules_get, update config.lua
#include "logwatch.h"

#include "../config.h"
#include "../log.h"

#include <assert.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;
}

struct logwatch_chan* logwatch_get_chan (struct logwatch *ctx, struct irc_chan *irc_chan)
{
    struct logwatch_chan *chan;
    
    // existing?
    if ((chan = logwatch_chan_lookup(ctx, irc_chan))) {
        // get ref
        chan->refcount++;

    } else {
        // create a new one with a ref
        // XXX: errors...
        chan = logwatch_chan_create(ctx, irc_chan);
    }

    // ok
    return chan;
}

void logwatch_on_line (struct logwatch *ctx, const struct logwatch_source *source, const char *line)
{
    const struct logwatch_filter *filter;
    struct error_info err;

    // apply each filter
    TAILQ_FOREACH(filter, &ctx->filters, logwatch_filters) {
        if (logwatch_filter_apply(filter, source, line, &err))
            log_warn("logwatch_filter_apply(%s, %s, %s): %s", filter->name, source->name, line, error_msg(&err));
    }
}


void logwatch_on_error (struct logwatch *ctx, const struct logwatch_source *source, const struct error_info *err)
{
    struct logwatch_chan *chan;
    
    // notify each relevant channel
    TAILQ_FOREACH(chan, &ctx->channels, logwatch_channels) {
        // skip irrelevant channels
        if (!logwatch_chan_has_source(chan, source))
            continue;

        // send an error message
        logwatch_chan_msg(chan, "!!! Source '%s' failed: %s", source->name, error_msg(err));
    }
}

/**
 * Add a logwatch_source with a FIFO at the given path
 */
static err_t logwatch_conf_source_fifo (void *_ctx, const struct config_option *option, const struct config_value values[], struct error_info *err)
{
    struct logwatch *ctx = _ctx;
    
    // parse arguments
    const char *path = config_get_string(option, values, "path");
    
    // open it
    if (logwatch_open_fifo(ctx, path, err) == NULL)
       return ERROR_CODE(err);

    // ok
    return SUCCESS;
}

/**
 * Add a logwatch_filter for the given bits
 */
static err_t logwatch_conf_filter (void *_ctx, const struct config_option *option, const struct config_value values[], struct error_info *err)
{
    struct logwatch *ctx = _ctx;
    struct logwatch_filter *filter;
    
    const struct logwatch_source *source = NULL;
    struct logwatch_chan *chan;
    const char *name, *source_name, *pattern, *format;
    struct irc_chan *irc_chan;

    // parse arguments
    name        = config_get_string     (option, values, "name"     );
    source_name = config_get_string     (option, values, "source"   );
    pattern     = config_get_string     (option, values, "pattern"  );
    format      = config_get_string     (option, values, "format"   );
    irc_chan    = config_get_irc_chan   (option, values, "chan"     );

    // lookup name
    if (source_name && (source = logwatch_source_lookup(ctx, source_name)) == NULL)
       RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "unknown logwatch_source name");
    
    // lookup the channel
    if ((chan = logwatch_get_chan(ctx, irc_chan)) == NULL)
        RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "logwatch_get_chan failed");
    
    log_info("add filter: name=%s, source=%s, pattern=%s, format=%s, chan=%s",
        name, source_name, pattern, format, irc_chan_name(irc_chan));

    // invoke
    if ((filter = logwatch_filter(ctx, name, source, pattern, format, chan, err)) == NULL)
        goto error;

    // ok
    return SUCCESS;

error:
    return ERROR_CODE(err);    
}

/**
 * Configuration options
 */
struct config_option logwatch_config_options[] = CONFIG_OPTIONS(
    CONFIG_OPT(         "source_fifo",  logwatch_conf_source_fifo,
        "read input lines from the FIFO at the given path",

        CONFIG_PARAM(       "path",     CONFIG_STRING,      "filesystem path to FIFO",                  false   )
    ),

    CONFIG_OPT(         "filter",       logwatch_conf_filter, 
        "filter lines from source (or all), using the given regular expression (or all lines), and format output "
        "using the given format expression (or pass through directly), and finally send the output to the given channel",

        CONFIG_PARAM(       "name",    CONFIG_STRING,      "filter name",                              false   ),
        CONFIG_PARAM(       "source",  CONFIG_STRING,      "optional logwatch_source to use",          true    ),
        CONFIG_PARAM(       "pattern", CONFIG_STRING,      "optional regular expression pattern",      true    ),
        CONFIG_PARAM(       "format",  CONFIG_STRING,      "optional output format",                   true    ),
        CONFIG_PARAM(       "chan",    CONFIG_IRC_CHAN,    "channel to send output to",                false   )
    )
);

static void logwatch_destroy (void *_ctx)
{
    struct logwatch *ctx = _ctx;
    struct logwatch_filter *filter;
    struct logwatch_source *source;

    // flush the filters list
    while ((filter = TAILQ_FIRST(&ctx->filters)))
        logwatch_filter_destroy(filter);

    // flush the sources list
    while ((source = TAILQ_FIRST(&ctx->sources)))
        logwatch_source_destroy(source);

    // release the context
    free(ctx);
}

/**
 * The module function table
 */
struct module_desc logwatch_module = {
    .init               = logwatch_init,
    .config_options     = logwatch_config_options,
    .unload             = NULL,
    .destroy            = logwatch_destroy
};