--- a/pvl/syslog/args.py Fri Jan 04 18:45:59 2013 +0200
+++ b/pvl/syslog/args.py Fri Jan 04 19:12:24 2013 +0200
@@ -73,6 +73,7 @@
)
filter = SyslogFilter(
+ # glob pattern
prog = options.syslog_prog,
)
--- a/pvl/syslog/filter.py Fri Jan 04 18:45:59 2013 +0200
+++ b/pvl/syslog/filter.py Fri Jan 04 19:12:24 2013 +0200
@@ -1,74 +1,111 @@
import logging; log = logging.getLogger('pvl.syslog.filter')
+import re # XXX
+import os.path, fnmatch
+
class SyslogFilter (object) :
"""
- Match syslog messages.
-
- XXX: do we need more than just prog?
+ Match syslog messages fields against given patterns.
"""
- def __init__ (self, prog=None) :
+ def __init__ (self, **filters) :
"""
- prog - match tag (process name)
+ Match using given { field: regex }.
"""
- self.prog = prog
+ self.filters = filters
- def match_prog (self, prog) :
+ def match_prog (self, attr, filter, prog=None) :
"""
- Match given prog?
+ XXX: Match given prog as glob?
"""
- if not self.prog :
- return
+ if not filter :
+ # ignore
+ return None
# normalize
- prog = prog.lower()
-
- if prog.startswith('/') :
- # base
- prog = prog.split('/')[-1]
+ prog = prog.strip().lower()
+ _, prog = os.path.split(prog)
# match
- if not prog :
- # never matches non-tagged lines
+ if fnmatch.fnmatch(prog, filter) :
+ return { attr: prog }
+ else :
return False
- elif self.prog.endswith('*') :
- # prefix match
- return prog.startswith(self.prog[:-1])
+ def match (self, attr, regex, value=None) :
+ """
+ Match given value against given pattern.
+ """
+ if not filter :
+ # ignore
+ return None
+
+ if not value :
+ # XXX: optional = match empty string?
+ value = ''
else :
- return prog == self.prog
+ # normalize; XXX: unicode?
+ value = str(value).strip()
+
+ # match
+ match = regex.match(value)
+
+ if match :
+ # as matche-values
+ match = match.groupdict()
+ match[attr] = value
+
+ return match
def filter (self, item) :
"""
- Match given item?
+ Match given item. Returns any matched values (including regexp capture groups) across all fields.
"""
- for attr, func in (
- ( 'prog', self.match_prog),
- ) :
- match = func(item[attr])
+ 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 :
- continue
+ # match
+ matches.update(match)
elif match is None :
- pass
+ # ignore
+ continue
else :
- break
+ # reject
+ return
- # ok
+ # XXX: test last match, in case they were all None
if match is None :
# XXX: empty filter!?
return True
else :
- return match
+ return matches
- def __call__ (self, items) :
+ def process (self, items) :
for item in items:
- if self.filter(item) :
+ match = self.filter(item)
+
+ if match :
yield item
-
+
+ __call__ = process