--- a/fixbot/logwatch/filters.py Thu Feb 04 20:14:22 2010 +0200
+++ b/fixbot/logwatch/filters.py Thu Feb 04 20:39:53 2010 +0200
@@ -1,66 +1,121 @@
import re
-class FullFilter (object) :
+class BaseFilter (object) :
+ """
+ A filter object matches incoming lines, to determine how they are handled, classify them, and optionally reformat them
+ """
+
+ # the LogWatchModule event to send
+ event_type = None
+
def __init__ (self, event_type) :
self.event_type = event_type
def test (self, line) :
- return line
+ """
+ Match against the given line, and return one of:
-class NullFilter (object) :
+ None - filter did not match, continue
+ False - filter matched, line should be dropped
+ (type, <str>)
+ - filter matched, pass formatted output
+ """
+
+ raise NotImplementedError()
+
+class FullFilter (BaseFilter) :
+ """
+ A trivial filter that matches every possible line as-is
+ """
+
+ def test (self, line) :
+ # pass through
+ return self.event_type, line
+
+class NullFilter (BaseFilter) :
+ """
+ A filter that drops every line matching a given regexp
+ """
+
def __init__ (self, pattern, flags=None) :
+ # don't need an event_type
+
self.regexp = re.compile(pattern, flags)
def test (self, line) :
match = self.regexp.search(line)
if match :
+ # drop
return False
-class SimpleFilter (object) :
- def __init__ (self, event_type, pattern, format) :
- self.event_type = event_type
+class SimpleFilter (BaseFilter) :
+ """
+ A simple filter that passes through any lines that match, optionally reformatting them with the given string
+ pattern, using the regexp match groups as parameters.
+ """
+ def __init__ (self, event_type, pattern, format=None) :
+ super(SimpleFilter, self).__init__(event_type)
+
+ # store
self.regexp = re.compile(pattern)
self.format = format
def test (self, line) :
+ # match
match = self.regexp.search(line)
- if match :
- return self._filter(match)
+ if not match :
+ # continue
+ return None
- def _filter (self, match) :
- return self.format % match.groupdict()
+ # reformat?
+ if self.format :
+ # format with regexp match groups
+ return self.event_type, self.format % match.groupdict()
+
+ else :
+ # match as-is
+ return self.event_type, line
+# matches a timestamp prefix
_timestamp = "\w{3} [0-9 ]\d \d{2}:\d{2}:\d{2}"
+
+# matches all lines
all = FullFilter("all")
+# match all lines, but drop the prefixed timestamp
all_wo_timestamps = SimpleFilter(
"all",
"^" + _timestamp + " (?P<line>.+)$",
"%(line)s"
)
+# match sudo invocations, reformatting them nicely
sudo = SimpleFilter(
"sudo",
"(?P<hostname>\S+)\s+sudo:\s*(?P<username>\S+) : TTY=(?P<tty>\S+) ; PWD=(?P<pwd>.+?) ; USER=(?P<target_user>\S+) ; COMMAND=(?P<command>.*)",
"%(username)s:%(tty)s - %(target_user)s@%(hostname)s:%(pwd)s - %(command)r"
)
+# match accepted ssh logins
ssh = SimpleFilter(
"ssh",
- "(?P<success>Accepted|Failed) password for (?P<username>\S+) from (?P<ip>\S+) port (?P<port>\S+) (?P<proto>\S+)",
- "%(success)s login for %(username)s from %(ip)s:%(port)s proto %(proto)s"
+ "Accepted password for (?P<username>\S+) from (?P<ip>\S+) port (?P<port>\S+) (?P<proto>\S+)",
+ "SSH login for %(username)s from %(ip)s:%(port)s"
)
+# drops pam output from cron
cron_killer = NullFilter(
"^" + _timestamp + " \S+\s+(CRON|su)\[\d+\]: pam_unix\(cron:\w+\): session (opened|closed) for user \w+( by \(uid=\d+\))?$",
re.IGNORECASE
)
+# drops `su nobody` output (from cron)
su_nobody_killer = NullFilter(
"^" + _timestamp + " \S+\s+su\[\d+\]: (Successful su for nobody by root|\+ \?\?\? root:nobody)$",
re.IGNORECASE
)
+