terom@119: #include "logwatch.h" terom@119: terom@119: #include "../config.h" terom@127: #include "../log.h" terom@119: terom@132: #include terom@132: terom@119: static err_t logwatch_init (struct nexus *nexus, void **ctx_ptr, struct error_info *err) terom@119: { terom@119: struct logwatch *ctx; terom@119: terom@119: // allocate terom@119: if ((ctx = calloc(1, sizeof(*ctx))) == NULL) terom@119: RETURN_SET_ERROR(err, ERR_CALLOC); terom@119: terom@119: // init terom@119: TAILQ_INIT(&ctx->sources); terom@119: TAILQ_INIT(&ctx->filters); terom@119: TAILQ_INIT(&ctx->channels); terom@119: terom@119: // store terom@119: ctx->nexus = nexus; terom@119: terom@119: // ok terom@119: *ctx_ptr = ctx; terom@119: terom@119: return SUCCESS; terom@119: } terom@119: terom@132: struct logwatch_chan* logwatch_get_chan (struct logwatch *ctx, struct irc_chan *irc_chan) terom@132: { terom@132: struct logwatch_chan *chan; terom@132: terom@132: // existing? terom@132: if ((chan = logwatch_chan_lookup(ctx, irc_chan))) { terom@132: // get ref terom@132: chan->refcount++; terom@132: terom@132: } else { terom@132: // create a new one with a ref terom@132: // XXX: errors... terom@132: chan = logwatch_chan_create(ctx, irc_chan); terom@132: } terom@132: terom@132: // ok terom@132: return chan; terom@132: } terom@132: terom@127: void logwatch_on_line (struct logwatch *ctx, const struct logwatch_source *source, const char *line) terom@127: { terom@127: const struct logwatch_filter *filter; terom@127: struct error_info err; terom@127: terom@127: // apply each filter terom@127: TAILQ_FOREACH(filter, &ctx->filters, logwatch_filters) { terom@127: if (logwatch_filter_apply(filter, source, line, &err)) terom@132: log_warn("logwatch_filter_apply(%s, %s, %s): %s", filter->name, source->name, line, error_msg(&err)); terom@127: } terom@127: } terom@127: terom@133: terom@132: void logwatch_on_error (struct logwatch *ctx, const struct logwatch_source *source, const struct error_info *err) terom@132: { terom@132: struct logwatch_chan *chan; terom@132: terom@132: // notify each relevant channel terom@133: TAILQ_FOREACH(chan, &ctx->channels, logwatch_channels) { terom@133: // skip irrelevant channels terom@133: if (!logwatch_chan_has_source(chan, source)) terom@133: continue; terom@133: terom@133: // send an error message terom@133: logwatch_chan_msg(chan, "!!! Source '%s' failed: %s", source->name, error_msg(err)); terom@133: } terom@132: } terom@132: terom@119: /** terom@119: * Add a logwatch_source with a FIFO at the given path terom@119: */ terom@132: static err_t logwatch_conf_source_fifo (void *_ctx, const struct config_option *option, const struct config_value values[], struct error_info *err) terom@119: { terom@119: struct logwatch *ctx = _ctx; terom@119: terom@132: // parse arguments terom@132: const char *path = config_get_string(option, values, "path"); terom@132: terom@119: // open it terom@119: if (logwatch_open_fifo(ctx, path, err) == NULL) terom@119: return ERROR_CODE(err); terom@119: terom@119: // ok terom@119: return SUCCESS; terom@119: } terom@119: terom@119: /** terom@121: * Add a logwatch_filter for the given bits terom@121: */ terom@121: static err_t logwatch_conf_filter (void *_ctx, const struct config_option *option, const struct config_value values[], struct error_info *err) terom@121: { terom@121: struct logwatch *ctx = _ctx; terom@121: struct logwatch_filter *filter; terom@121: terom@132: const struct logwatch_source *source = NULL; terom@132: struct logwatch_chan *chan; terom@132: const char *name, *source_name, *pattern, *format; terom@132: struct irc_chan *irc_chan; terom@121: terom@121: // parse arguments terom@132: name = config_get_string (option, values, "name" ); terom@132: source_name = config_get_string (option, values, "source" ); terom@132: pattern = config_get_string (option, values, "pattern" ); terom@132: format = config_get_string (option, values, "format" ); terom@132: irc_chan = config_get_irc_chan (option, values, "chan" ); terom@132: terom@132: // lookup name terom@132: if (source_name && (source = logwatch_source_lookup(ctx, source_name)) == NULL) terom@132: RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "unknown logwatch_source name"); terom@132: terom@132: // lookup the channel terom@132: if ((chan = logwatch_get_chan(ctx, irc_chan)) == NULL) terom@132: RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "logwatch_get_chan failed"); terom@130: terom@121: // invoke terom@121: if ((filter = logwatch_filter(ctx, name, source, pattern, format, chan, err)) == NULL) terom@121: goto error; terom@121: terom@121: // ok terom@121: return SUCCESS; terom@121: terom@121: error: terom@121: return ERROR_CODE(err); terom@121: } terom@121: terom@121: /** terom@119: * Configuration options terom@119: */ terom@121: struct config_option logwatch_config_options[] = CONFIG_OPTIONS( terom@132: CONFIG_OPT( "source_fifo", logwatch_conf_source_fifo, terom@132: "read input lines from the FIFO at the given path", terom@132: terom@132: CONFIG_PARAM( "path", CONFIG_STRING, "filesystem path to FIFO", false ) terom@132: ), terom@119: terom@121: CONFIG_OPT( "filter", logwatch_conf_filter, terom@124: "filter lines from source (or all), using the given regular expression (or all lines), and format output " terom@124: "using the given format expression (or pass through directly), and finally send the output to the given channel", terom@121: terom@121: CONFIG_PARAM( "name", CONFIG_STRING, "filter name", false ), terom@132: CONFIG_PARAM( "source", CONFIG_STRING, "optional logwatch_source to use", true ), terom@121: CONFIG_PARAM( "pattern", CONFIG_STRING, "optional regular expression pattern", true ), terom@121: CONFIG_PARAM( "format", CONFIG_STRING, "optional output format", true ), terom@121: CONFIG_PARAM( "chan", CONFIG_IRC_CHAN, "channel to send output to", false ) terom@121: ) terom@121: ); terom@119: terom@119: static void logwatch_destroy (void *_ctx) terom@119: { terom@119: struct logwatch *ctx = _ctx; terom@132: struct logwatch_filter *filter; terom@119: struct logwatch_source *source; terom@119: terom@132: // flush the filters list terom@132: while ((filter = TAILQ_FIRST(&ctx->filters))) terom@132: logwatch_filter_destroy(filter); terom@132: terom@119: // flush the sources list terom@119: while ((source = TAILQ_FIRST(&ctx->sources))) terom@119: logwatch_source_destroy(source); terom@132: terom@132: // release the context terom@132: free(ctx); terom@119: } terom@119: terom@119: /** terom@119: * The module function table terom@119: */ terom@119: struct module_desc logwatch_module = { terom@119: .init = logwatch_init, terom@119: .config_options = logwatch_config_options, terom@132: .unload = NULL, terom@119: .destroy = logwatch_destroy terom@119: }; terom@119: