pvl/syslog/filter.py
author Tero Marttila <terom@paivola.fi>
Thu, 10 Jan 2013 17:51:53 +0200
changeset 74 952ee07efd7a
parent 68 bea41de5cc98
child 99 8d60eb5604e4
permissions -rw-r--r--
pvl.syslog: implement --syslog-facility, implementing proper glob/regexp support in SyslogFilter
import logging; log = logging.getLogger('pvl.syslog.filter')

import re # XXX
import os.path, fnmatch

class SyslogFilter (object) :
    """
        Match syslog messages fields against given patterns.
    """

    def __init__ (self, **filters) :
        """
            Match using given { field: regex }.
        """
        
        # drop None's
        self.filters = dict((attr, regex) for attr, regex in filters.iteritems() if regex is not None)

    def match_glob (self, attr, glob, value=None) :
        """
            Match prog as glob.
        """

        if not value :
            # require
            return False

        # normalize
        value = value.strip()

        # match
        if fnmatch.fnmatch(value, glob) :
            return { attr: value }
        else :
            return False
 
    match_facility = match_glob

    def match_prog (self, attr, glob, prog=None) :
        """
            Match prog as glob.
        """

        if prog :
            # normalize
            prog = prog.strip().lower()
            _, prog = os.path.split(prog)

        # match
        return self.match_glob(attr, glob, prog)

    REGEX_TYPE = type(re.compile(''))

    def match_regex (self, attr, regex, value=None) :
        """
            Match given value against given pattern.
        """

        if not value :
            # XXX: optional = match empty string?
            value = ''
        else :
            # normalize; XXX: unicode?
            value = str(value).strip()
        
        # match
        match = regex.match(value)

        if not match :
            return False

        # as match-values
        matches = match.groupdict()
        matches[attr] = match.group(0) # whole match

        # TODO match.expand?

        return matches

    def filter (self, item) :
        """
            Match given item. Returns any matched values (including regexp capture groups) across all fields.
        """

        match = None
        matches = {}

        for attr in self.filters :
            # filter
            filter = self.filters[attr]

            if not filter :
                # ignore
                continue
            
            # lookup match-func
            match = getattr(self, 'match_{attr}'.format(attr=attr), None)

            if match :
                pass

            elif isinstance(filter, self.REGEX_TYPE) :
                match = self.match_regex

            else :
                match = self.match_glob

            # apply match
            if attr in item :
                match = match(attr, filter, item[attr])
            else :
                match = match(attr, filter)

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

            if match :
                # match
                matches.update(match)
            
            else :
                # reject
                return
        
        # test last match
        if match is None :
            # empty filter -> all None
            return True
        else :
            return matches

    def process (self, items) :
        for item in items:
            match = self.filter(item)

            if match :
                yield item
    
    __call__ = process

    def __nonzero__ (self) :
        return bool(self.filters)

    def __repr__ (self) :
        return repr(self.filters)