pvl.syslog: nested sections
authorTero Marttila <terom@fixme.fi>
Fri, 04 Jan 2013 22:32:14 +0200
changeset 66 1e3a144f25c0
parent 65 be2b407c06ff
child 67 3324ed10c42f
pvl.syslog: nested sections
bin/pvl.verkko-syslog
etc/syslog.conf
pvl/syslog/rule.py
--- 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) :