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)