--- a/bin/pvl.verkko-syslog Thu Jan 10 17:52:43 2013 +0200
+++ b/bin/pvl.verkko-syslog Thu Jan 10 17:54:55 2013 +0200
@@ -39,6 +39,9 @@
parser.add_option_group(pvl.syslog.rule.parser(parser))
parser.add_option_group(pvl.irker.parser(parser))
+ parser.add_option('--irker-target', metavar='IRC',
+ help="Irker target URL")
+
# parse
options, args = parser.parse_args(argv[1:])
@@ -63,28 +66,20 @@
rules = pvl.syslog.rule.apply(options)
log.info("Connect IRK..")
- irk, target = pvl.irker.apply(options, target=target)
+ irk = pvl.irker.apply(options)
-
log.info("Process syslog messages...")
for item in syslog.main() :
- match = rules.apply(item)
-
- if match :
- rule = str(match.get('rule'))
+ match, rulepath, apply = rules.apply(item)
- out = { rule: match.get(rule) }
- else :
- out = { }
-
- log.info("%s: %s", item, out)
+ log.info("%s: %s", item, apply)
+
+ target = apply.get('irk', options.irker_target)
+
+ tag = '/'.join(str(rule) for rule in reversed(rulepath[:-1]))
+ text = apply.get('text')
- for tag, message in out.iteritems() :
- # TODO: map tag -> target?
- if target :
- target(message)
- else :
- print tag, message
+ print target, tag, text
# done
log.info("Exiting...")
--- a/pvl/syslog/rule.py Thu Jan 10 17:52:43 2013 +0200
+++ b/pvl/syslog/rule.py Thu Jan 10 17:54:55 2013 +0200
@@ -30,6 +30,9 @@
else :
return SyslogRule('default', formats={ 'default': '{msg}' })
+def merge (*dicts, **kwargs) :
+ return dict((k, v) for d in (dicts + (kwargs, )) for k, v in d.iteritems())
+
# TODO: combine SyslogRule/Rules into one heirarchial SyslogRule -type?
class SyslogRule (object) :
"""
@@ -55,29 +58,34 @@
rules = [cls.config_section(subsection, section[subsection]) for subsection in section.sections]
attrs = dict((name, section[name]) for name in section.scalars)
- return cls.config(name, rules=rules, **attrs)
+ return cls.config(name, rules, **attrs)
@classmethod
- def config (cls, name, format=None, program=None, pattern=None, rules=None, **filters) :
+ def config (cls, name, rules=None, format=None, irk=None, program=None, facility=None, pattern=None, **filters) :
"""
Build SyslogRule from config options
"""
- if pattern :
- pattern = re.compile(pattern)
+ if format :
+ format = { 'text': format }
+ else :
+ format = { }
- if format :
- format = { name: format }
+ if irk :
+ format['irk'] = irk
filters = dict(
(attr, re.compile(regex)) for attr, regex in filters.iteritems()
)
+ if facility :
+ filters['facility'] = facility # glob
+
if program :
- filters['prog'] = program
+ filters['prog'] = program # glob
if pattern :
- filters['msg'] = pattern
+ filters['msg'] = re.compile(pattern)
filter = SyslogFilter(**filters)
@@ -93,7 +101,7 @@
def match (self, item) :
"""
- Match item against our filter, applying any matches.
+ Match item against our filter, returning match-dict (empty?) or None.
"""
if self.filter :
@@ -101,75 +109,75 @@
matches = self.filter.filter(item)
else :
- # match all
- matches = True
+ # match all, we probably have sub-rules that we're interested in
+ return { }
log.debug("%s: %s", self, matches)
- if not matches :
- # ignore
+ if matches :
+ return matches
+ else :
+ # no match
return None
- # apply
- item['rule'] = self
-
- if matches is True :
- # no-op filter
- pass
- else :
- item.update(matches)
-
- # XXX: copy, not mutate?
- return item
-
def format (self, item) :
"""
- Apply output formats
+ Apply our output formats to given base apply, yielding (unique) attr, value tuples.
"""
-
- out = {}
for attr, format in self.formats.iteritems() :
- value = out[attr] = format.format(**item)
+ value = format.format(**item)
+
log.debug("%s: %s: %s", self, attr, value)
-
- return out
- # TODO: __call__?
+ yield attr, value
+
def apply (self, item) :
"""
- Match item against ourself, apply against any sub-rules, and return output, if hit.
+ Recursively match item against ourself and sub-rules. Returns applied output.
+
+ Matches are passed down the tree, and applies are passed up.
"""
- item = self.match(item)
+ log.debug("%s", self)
- if not item :
+ # match rule -> matches
+ matches = self.match(item)
+
+ if matches is None :
# skip
- return
+ return None, None, None
+
+ # merge matches down
+ item = merge(item, matches)
- # sub-rules
+ # recursive sub-rules -> apply
for rule in self.rules :
try :
- out = rule.apply(item)
+ # pass matches down
+ match, rules, apply = rule.apply(item)
except Exception as ex :
- log.exception("rule %s: %r", rule, item)
- return # XXX: skip?
+ log.exception("%s -> %s: %r", self, rule, item)
+ continue # XXX: skip?
- if out :
- # hit
- return out
-
- # TODO: routing/formatting
- #if self.tag is False :
- # # drop
- # return False
-
+ if apply :
+ # pass apply up
+ break
+ else :
+ # self-match
+ match, rules, apply = item, [], { }
+
+ rules.append(self)
+
+ # formats?
if self.formats :
- # hit
- item.update(self.format(item))
+ # merge apply up
+ apply = merge(dict(self.format(item)), apply)
- return item
+ log.debug("%s: %s", '/'.join(str(rule) for rule in rules), apply)
+
+ return match, rules, apply
def __iter__ (self, items) :
"""
@@ -177,10 +185,10 @@
"""
for item in items :
- match = self.apply(item)
+ match, rules, apply = self.apply(item)
- if match :
- yield match
+ if apply :
+ yield apply
def __str__ (self) :
return self.name