pvl/syslog/rule.py
author Tero Marttila <terom@fixme.fi>
Fri, 04 Jan 2013 18:45:59 +0200
changeset 51 96d204b146b4
parent 48 40ccb8d3c96e
child 55 cbdd49b76f16
permissions -rw-r--r--
pvl.syslog.rule: refactor rule-config loading
from pvl.syslog.filter import SyslogFilter

import re

import optparse, sys

import logging; log = logging.getLogger('pvl.syslog.rule')

# XXX: ConfigParser kinda sucks
import ConfigParser

def parser (parser) :
    """
        Optparse option group.
    """

    syslog_rules = optparse.OptionGroup(parser, "Syslog rules")
    
    syslog_rules.add_option('--syslog-rules', metavar='FILE',
            help="Load syslog rules from file")

    return syslog_rules

def apply (options) :
    """
        Build SyslogRules from options.
    """
    
    if options.syslog_rules :
        return SyslogRules.load(open(options.syslog_rules))

    else :
        return None

# TODO: combine SyslogRule/Rules into one heirarchial SyslogRule -type?
class SyslogRule (object) :
    """
        A rule matches syslog lines, and formats them.
            
            tag         - apply given tag to matches
    """

    def __init__ (self, tag, program=None, pattern=None, format=None, flags=0) :
        log.debug("%s: %s", tag, pattern)
        
        if pattern :
            pattern = re.compile(pattern, flags)

        self.filter = SyslogFilter(prog=program)

        self.tag = tag
        self.format = format
        self.pattern = pattern

    def apply (self, item) :
        """
            Apply rule against given item.

            Returns
                None        - skip
                False       - drop
                (tag, line) - output
        """
        
        # filter
        match = self.filter.filter(item)

        if not match :
            # ignore
            return None
        
        if self.pattern :
            match = self.pattern.match(item['msg'])

            if not match :
                # ignore
                return None
            
            # apply
            item.update(match.groupdict())

        if self.tag is False :
            # drop
            return False
            
        if self.format :
            # return
            return self.tag, self.format.format(**item)
        
    def __str__ (self) :
        return self.tag

class SyslogRules (object) :
    """
        Apply a set of rules against lines.
    """

    @classmethod
    def load (cls, file) :
        """
            Load rules from file.
        """
        config = ConfigParser.RawConfigParser()
        config.readfp(file)
        
        # XXX: ordered in python2.7, unordered in python2.6 !
        rules = [SyslogRule(section, **dict(config.items(section))) for section in config.sections()]

        return cls(rules)

    def __init__ (self, rules) :
        self.rules = rules

    def apply (self, item) :
        """
            Apply item against our rules, returning the first match (False/tag-line).
        """

        for rule in self.rules :
            try :
                match = rule.apply(item)

            except Exception as ex :
                log.exception("rule %s: %r", rule, item)
                continue

            log.debug("%s: %s", rule, match)

            if match is None :
                continue
            else :
                break
        
        return match

    def process (self, items) :
        """
            Apply items against our rules, yielding any matches.
        """

        for item in items :
            match = self.apply(item)

            if match :
                yield match