pvl/syslog/filter.py
author Tero Marttila <terom@fixme.fi>
Fri, 04 Jan 2013 21:12:18 +0200
changeset 56 ff184e09ceb9
parent 54 9c82a068f8f9
child 57 c88861dda326
permissions -rw-r--r--
pvl.syslog.filter: fix true/false/filenotfound snafu
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 }.
        """
        
        self.filters = filters

    def match_prog (self, attr, glob, prog=None) :
        """
            XXX: Match given prog as glob?
        """

        if not glob :
            # ignore
            return None

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

        # match
        if fnmatch.fnmatch(prog, glob) :
            return { attr: prog }
        else :
            return False

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

        if not regex :
            # ignore
            return None

        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.
        """

        matches = {}

        for attr in self.filters :
            # lookup match-func
            match = getattr(self, 'match_{attr}'.format(attr=attr), self.match)

            # filter
            filter = self.filters[attr]
            
            # 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)
            
            elif match is None :
                # ignore
                continue

            else :
                # reject
                return
        
        # XXX: test last match, in case they were all None
        if match is None :
            # XXX: empty filter!?
            return True
        else :
            return matches

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

            if match :
                yield item
    
    __call__ = process