pvl/syslog/rule.py
author Tero Marttila <terom@fixme.fi>
Fri, 04 Jan 2013 20:51:12 +0200
changeset 55 cbdd49b76f16
parent 51 96d204b146b4
child 58 64885a7c6e85
permissions -rw-r--r--
pvl.syslog.rule: refactor SyslogRule
from pvl.syslog.filter import SyslogFilter

import re

import optparse, sys
import configobj

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

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 SyslogRule.load(open(options.syslog_rules))

    else :
        return SyslogRule('default')

# TODO: combine SyslogRule/Rules into one heirarchial SyslogRule -type?
class SyslogRule (object) :
    """
        A named SyslogFilter with sub-rules.
    """

    @classmethod
    def load (cls, file) :
        """
            Load SyslogRule from file.
        """

        config = configobj.ConfigObj(file)
        
        rules = [SyslogRule.config(section, **dict(config[section])) for section in config.sections]

        return cls(file.name, rules)

    @classmethod
    def config (cls, name, format=None, program=None, pattern=None, **filters) :
        """
            Build SyslogRule from config options
        """

        if pattern :
            pattern = re.compile(pattern)

        # XXX: rules/sub-sections support?
        rules = ()

        filters = dict(
            (cls.ATTRS.get(attr, attr), re.compile(regex)) for attr, regex in filters.iteritems()
        )

        filter = SyslogFilter(prog=program, msg=pattern, **filters)

        return cls(name, rules, filter)

    def __init__ (self, name, rules=None, filter=None) :
        log.debug("%s: %s", name, filter)
        
        self.name = name
        self.rules = rules or [] # sub-rules
        self.filter = filter # SyslogFilter

    def match (self, item) :
        """
            Match item against our filter, applying any matches.
        """
        
        if self.filter :
            # filter
            matches = self.filter.filter(item)

            if not matches :
                # ignore
                return None
        else :
            # match all
            matches = True

        # apply
        item['rule'] = self

        if matches is True :
            # no-op filter
            pass
        else :
            log.debug("%s: %s", self, matches)
            item.update(matches)
        
        # XXX: copy, not mutate?
        return item
    
    # TODO: __call__?
    def apply (self, item) :
        """
            Match item against ourselfs, apply against any sub-rules, and return XXX
        """

        item = self.match(item)

        if not item :
            return

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

            except Exception as ex :
                log.exception("rule %s: %r", rule, item)
                return # XXX: skip?

            if match is None :
                continue
            else :
                item = match
            
        log.debug("%s: %s", self, item)
       
        # TODO: routing/formatting
        """
        if self.tag is False :
            # drop
            return False
            
        if self.format :
            # return
            return self.tag, self.format.format(**item)
        """
        
        return item

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

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

            if match :
                yield match
 
    def __str__ (self) :
        return self.name
    
    def __repr__ (self) :
        return 'SyslogRule({self.name}, ...)'.format(self=self)