--- a/fixbot/logwatch/filters.py Fri Feb 05 20:38:44 2010 +0200
+++ b/fixbot/logwatch/filters.py Fri Feb 05 21:16:19 2010 +0200
@@ -13,15 +13,22 @@
def test (self, line) :
"""
- Match against the given line, and return one of:
+ Match against the given line. See match() for return codes
+ """
+ raise NotImplementedError()
+
+ def match (self, msg) :
+ """
+ Match against the given SyslogMessage, and return one of:
None - filter did not match, continue
False - filter matched, line should be dropped
(type, <str>)
- filter matched, pass formatted output
"""
-
- raise NotImplementedError()
+
+ # default to a full-line match
+ return self.test(str(msg))
class FullFilter (BaseFilter) :
"""
@@ -37,7 +44,7 @@
A filter that drops every line matching a given regexp
"""
- def __init__ (self, pattern, flags=None) :
+ def __init__ (self, pattern, flags=0) :
# don't need an event_type
self.regexp = re.compile(pattern, flags)
@@ -79,6 +86,69 @@
# match as-is
return self.event_type, line
+class SyslogFilter (BaseFilter) :
+ """
+ A more advanced filter that can match against fields in the syslog message.
+ """
+
+ def __init__ (self, label, pattern=None, program=None, drop=False, format=None, re_flags=0) :
+ """
+ Filter using the given criteria:
+
+ label - label match output with given label
+
+ pattern - match message content against given regexp
+ program - (optional) case-insensitive match against message tag's program component
+ May also be False to indicate no tag
+
+ drop - drop this message if this matches
+ format - (optional) format output with given format string
+
+ re_flags - (optional) flags for regular expression
+ """
+
+ # XXX: super(SyslogFilter, self).__init__(label)
+ self.label = label
+
+ # store
+ self.regexp = re.compile(pattern, re_flags)
+ self.program = program
+
+ self.drop = drop
+ self.format = format
+
+ def match (self, msg) :
+ """
+ Evaluate match on given message
+ """
+
+ # use the SyslogMessage's match method
+ match = msg.match(self.regexp, self.program)
+
+ # handle result
+ if match is False :
+ # nack
+ return None
+
+ elif self.drop :
+ # halt processing
+ return False
+
+ elif self.format :
+ # the messages properties
+ params = msg.properties()
+
+ # the regexp'd matched params
+ params.update(match)
+
+ # formatted output
+ return self.label, self.format % params
+
+ else :
+ # boring output
+ return self.label, str(msg)
+
+
# matches a timestamp prefix
_timestamp = "\w{3} [0-9 ]\d \d{2}:\d{2}:\d{2}"
@@ -94,12 +164,18 @@
)
# 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"
+sudo = SyslogFilter('sudo',
+ program = "sudo",
+ pattern = "^\s*(?P<username>\S+) : TTY=(?P<tty>\S+) ; PWD=(?P<pwd>.+?) ; USER=(?P<target_user>\S+) ; COMMAND=(?P<command>.*)",
+ format = "%(username)s:%(tty)s - %(target_user)s@%(hostname)s:%(pwd)s - %(command)r",
)
+#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",
--- a/fixbot/logwatch/message.py Fri Feb 05 20:38:44 2010 +0200
+++ b/fixbot/logwatch/message.py Fri Feb 05 21:16:19 2010 +0200
@@ -71,7 +71,7 @@
+ r"(?P<timestamp>\w{3} [0-9 ]\d \d{2}:\d{2}:\d{2}) (?P<hostname>\S+)"
# the message, including possible tag/pid
- + r" (?P<message>(?P<tag>(?P<program>[^:\]]+)(?:\[(?P<pid>\d+)\])?: )?(?P<text>.+))\n?"
+ + r" (?P<message>(?P<tag>(?P<program>[^:\]]+)(?:\[(?P<pid>\d+)\])?: )?(?P<text>.*))\n?"
)
# strptime format of timestamp
@@ -158,7 +158,65 @@
# the raw line as matched
self.raw = match.group(0)
+
+ def properties (self) :
+ """
+ Return a dict containing the attributes specified for this message
+ """
+
+ # XXX: ugh... doesn't do @property
+ return dict(
+ facility = self.facility,
+ priority = self.priority,
+ timestamp = self.timestamp,
+ hostname = self.hostname,
+ tag = self.tag,
+ program = self.program,
+ pid = self.pid,
+ text = self.text,
+ message = self.message,
+ )
+ def match (self, regexp=None, program=None) :
+ """
+ Evaluate a match against this message using the given criteria
+
+ regexp - match regexp against the message's contents
+ program - match program component of tag against given value, may also be False
+ """
+
+ params = {}
+
+ ## program
+ if program is False :
+ # only match if no tag
+ if self.program is not None :
+ return False
+
+ elif program is not None :
+ # case-insensitive match
+ if self.program.lower() != program.lower() :
+ return False
+
+ else :
+ # params
+ params['program'] = self.program
+
+ ## pattern
+ if regexp is not None :
+ # apply regexp
+ match = regexp.match(self.text)
+
+ if not match :
+ # no match
+ return False
+
+ # good, params
+ params.update(match.groupdict())
+
+ # we appear to have a match
+ return params
+
def __str__ (self) :
"""
Format to default format
--- a/fixbot/logwatch/sources.py Fri Feb 05 20:38:44 2010 +0200
+++ b/fixbot/logwatch/sources.py Fri Feb 05 21:16:19 2010 +0200
@@ -81,7 +81,7 @@
for filter in self.filters :
# let the filter process the line
- out = filter.test(line)
+ out = filter.match(msg)
if out :
# unpack