--- a/bin/pvl.verkko-syslog Fri Jan 04 22:25:20 2013 +0200
+++ b/bin/pvl.verkko-syslog Fri Jan 04 22:32:14 2013 +0200
@@ -68,28 +68,23 @@
log.info("Process syslog messages...")
for item in syslog.main() :
- item = rules.apply(item)
-
- if not item :
- continue
-
- log.info("%s", item)
-
- rule = item.get('rule')
+ match = rules.apply(item)
- if rule :
- out = item.get(str(rule))
- else :
- out = None
+ log.info("%s: %s", item, match)
+
+ if not match :
+ continue
+
+ rule = str(match.get('rule'))
- if not out :
- continue
+ out = { rule: match.get(rule) }
- # TODO: map tag -> target?
- if target :
- target(out)
- else :
- print rule, out
+ for tag, message in out.iteritems() :
+ # TODO: map tag -> target?
+ if target :
+ target(message)
+ else :
+ print tag, message
# done
log.info("Exiting...")
--- a/etc/syslog.conf Fri Jan 04 22:25:20 2013 +0200
+++ b/etc/syslog.conf Fri Jan 04 22:32:14 2013 +0200
@@ -1,24 +1,21 @@
-format = {host} {msg}
-
[sudo]
program = sudo
-pattern = ^\s*(?P<login>\S+) : TTY=(?P<tty>\S+) ; PWD=(?P<pwd>.+?) ; USER=(?P<user>\S+) ; (?:ENV=(?P<env>.+?) ; )?COMMAND=(?P<command>.*)
+[[sudo_command]]
+pattern = (?P<login>\S+) : TTY=(?P<tty>\S+) ; PWD=(?P<pwd>.+?) ; USER=(?P<user>\S+) ; (?:ENV=(?P<env>.+?) ; )?COMMAND=(?P<command>.*)
format = {login}:{tty} - {user}@{host}:{pwd} - {command!r}
-#pattern = \s*(?P<login>\S+) : TTY=(?P<tty>\S+)\s; PWD=(?P<pwd>.+?)\s; USER=(?P<user>\S+)\s;( COMMAND=(?P<command>.*)
-
-[puppet_readshadow]
-rule = sudo
+[[[puppet_readshadow]]]
login = puppet
user = root
command = /usr/bin/getent shadow \w+
-format =
+[[sudo_unknown]]
+format = {host} {msg}
[ssh]
program = sshd
-pattern = \s*Accepted password for (?P<user>\S+) from (?P<ip>\S+) port (?P<port>\S+) (?P<proto>\S+)
+pattern = Accepted password for (?P<user>\S+) from (?P<ip>\S+) port (?P<port>\S+) (?P<proto>\S+)
format = SSH login for {user}@{host} from {ip}
[cron]
@@ -30,3 +27,7 @@
[puppet]
program = puppet
+
+[all]
+format = {host} {msg}
+
--- a/pvl/syslog/rule.py Fri Jan 04 22:25:20 2013 +0200
+++ b/pvl/syslog/rule.py Fri Jan 04 22:32:14 2013 +0200
@@ -43,11 +43,19 @@
"""
config = configobj.ConfigObj(file)
-
- # TODO: sub-sections -> rules?
- rules = [cls.config(section, **dict(config[section])) for section in config.sections]
-
- return cls.config(file.name, rules=rules, **dict((name, config[name]) for name in config.scalars))
+
+ return cls.config_section(file.name, config)
+
+ @classmethod
+ def config_section (cls, name, section) :
+ """
+ Recursively load Syslogrules from config section.
+ """
+
+ 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)
@classmethod
def config (cls, name, format=None, program=None, pattern=None, rules=None, **filters) :
@@ -72,16 +80,16 @@
filters['msg'] = pattern
filter = SyslogFilter(**filters)
+
+ log.debug("%s: %s %s", name, rules, filter)
return cls(name, rules, filter, format)
- def __init__ (self, name, rules=None, filter=None, formats=None) :
- log.debug("%s: %s", name, filter)
-
+ def __init__ (self, name, rules=None, filter=None, formats=None) :
self.name = name
self.rules = rules or [] # sub-rules
self.filter = filter # SyslogFilter
- self.formats = formats
+ self.formats = formats or {}
def match (self, item) :
"""
@@ -118,37 +126,39 @@
"""
Apply output formats
"""
+
+ out = {}
for attr, format in self.formats.iteritems() :
- value = item[attr] = format.format(**item)
+ value = out[attr] = format.format(**item)
log.debug("%s: %s: %s", self, attr, value)
- return item
+ return out
# TODO: __call__?
def apply (self, item) :
"""
- Match item against ourselfs, apply against any sub-rules, and return XXX
+ Match item against ourself, apply against any sub-rules, and return output, if hit.
"""
item = self.match(item)
if not item :
+ # skip
return
# sub-rules
for rule in self.rules :
try :
- match = rule.apply(item)
+ out = 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
+ if out :
+ # hit
+ return out
# TODO: routing/formatting
#if self.tag is False :
@@ -156,8 +166,9 @@
# return False
if self.formats :
- item = self.format(item)
-
+ # hit
+ item.update(self.format(item))
+
return item
def __iter__ (self, items) :