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)