/**
* @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 "../line_proto.h"
#include "../nexus.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 we are registered to */
struct logwatch *ctx;
/** Our name */
char *name;
/** 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
/**
* Logwatch's per-channel state
*/
struct logwatch_chan {
/** The logwatch context we are registered to */
struct logwatch *ctx;
/** The actual irc_chan */
struct irc_chan *irc_chan;
/** Number of references */
size_t refcount;
/** Our entry in logwatch::channels */
TAILQ_ENTRY(logwatch_chan) logwatch_channels;
};
/**
* Maximum length of a logwatch_chan message, not including NUL byte
*
* XXX: this is a bad way to handle truncation
*/
#define LOGWATCH_CHAN_MSG_MAX 470
/**
* A filter specifies what lines to match, and how to then format the output.
*/
struct logwatch_filter {
/** The logwatch context we are registered to */
struct logwatch *ctx;
/** The name of the filter */
char *name;
/** The source to restrict this to, if any */
const struct logwatch_source *source;
/**
* The compiled regular expression to match, or NULL to match all lines.
*/
pcre *regexp;
/**
* The output format string, or NULL to send the line itself as-is
*/
char *format;
/**
* The channel to send output to
*/
struct logwatch_chan *chan;
/** Our entry in logwatch::filters */
TAILQ_ENTRY(logwatch_filter) logwatch_filters;
};
/**
* Maximum number of capture groups in the filter's regexp
*/
#define LOGWATCH_FILTER_GROUPS_MAX 16
/**
* Maximum length of logwatch_filter output
*/
#define LOGWATCH_FILTER_OUT_MAX 450
/**
* 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 chanenls */
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, also used as the name
* @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);
/**
* Lookup a logwatch_source by name
*/
const struct logwatch_source* logwatch_source_lookup (struct logwatch *ctx, const char *name);
/**
* Returns true if the given chan is linked to the given source via at least one filter
*/
bool logwatch_chan_has_source (struct logwatch_chan *chan, const struct logwatch_source *source);
/**
* Look for an existing logwatch_chan entry, returning it if it exists
*/
struct logwatch_chan* logwatch_chan_lookup (struct logwatch *ctx, struct irc_chan *irc_chan);
/**
* Create a new irc_chan with an initial refcount of one.
*
* @returns NULL on ERR_CALLOC
*/
struct logwatch_chan* logwatch_chan_create (struct logwatch *ctx, struct irc_chan *irc_chan);
/**
* Returns a logwatch_chan reference, destroying as needed.
*/
void logwatch_chan_put (struct logwatch_chan *chan);
/**
* Send a notice of at most LOGWATCH_CHAN_MSG_MAX bytes to the channel using the given format string.
*/
err_t logwatch_chan_msg (struct logwatch_chan *chan, const char *fmt, ...);
/**
* Find an existing logwatch_chan for the given channel, or create a new one. Returns a real reference that should be
* returned using logwatch_put_chan().
*
* @returns NULL on ERR_CALLOC
*/
struct logwatch_chan* logwatch_get_chan (struct logwatch *ctx, struct irc_chan *irc_chan);
/**
* Lookup an existing filter by name.
*/
struct logwatch_filter* logwatch_filter_lookup (struct logwatch *ctx, const char *name);
/**
* Add a new filter.
*
* The given logwatch_chan should be a new reference.
*/
struct logwatch_filter* logwatch_filter (struct logwatch *ctx, const char *name, const struct logwatch_source *source,
const char *pattern, const char *format, struct logwatch_chan *chan, struct error_info *err);
/**
* Destroy a logwatch_filter, unregistering it
*/
void logwatch_filter_destroy (struct logwatch_filter *filter);
/**
* Pass the given line (from the given source) through the given filter.
*
* Returns 0 if the next filter should be tried, >0 if no more filters should be processed, and -err_t on error.
*/
int logwatch_filter_apply (const struct logwatch_filter *filter, const struct logwatch_source *source, const char *line, struct error_info *err);
/**
* Remove any filters registered with the given source
*/
void logwatch_filter_remove (struct logwatch *ctx, const struct logwatch_source *source);
/**
* Handle a line from the given source by applying it to all filters.
*/
void logwatch_on_line (struct logwatch *ctx, const struct logwatch_source *source, const char *line);
/**
* Handle a disasterous error on a logwatch_source by notifying any irc_chan's that it is linked to via our filters.
*
* The logwatch_source will dispose of itself after this.
*/
void logwatch_on_error (struct logwatch *ctx, const struct logwatch_source *source, const struct error_info *err);