# HG changeset patch # User Tero Marttila # Date 1265305251 -7200 # Node ID b9fdb77107681ae2d1f1301c2cb2361f5967ddc5 # Parent e82b6df5baa369c24adc5b9e12d965643ea2a3b3 move logwatch*.py to separate fixbot.logwatch package, and move logwatch_sources to etc/fixbot-logwatch.py diff -r e82b6df5baa3 -r b9fdb7710768 etc/fixbot-logwatch.py --- a/etc/fixbot-logwatch.py Thu Feb 04 19:39:37 2010 +0200 +++ b/etc/fixbot-logwatch.py Thu Feb 04 19:40:51 2010 +0200 @@ -1,19 +1,15 @@ -import logwatch_filters as filters -from logwatch_sources import * - -def sources () : - """ - Return a sequence of LogSource objects - """ +from fixbot.logwatch import filters +from fixbot.logwatch.sources import * - return ( - Fifo("auth", "logs/auth.fifo", ( - filters.sudo, - filters.cron_killer, - filters.all, - )), - Fifo("foo", "foo", ( - filters.all, - )), - ) +## shared secret for API client +api_secret = "xyz" +## Path to logfiles +logwatch_dir = "logs/" + +## Iterable of LogSource objects +logwatch_sources = ( + Fifo("test", logwatch_dir + "/test.fifo", ( + filters.all, + )), +) diff -r e82b6df5baa3 -r b9fdb7710768 fixbot/logwatch.py --- a/fixbot/logwatch.py Thu Feb 04 19:39:37 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -from twisted.internet import protocol, reactor -from twisted.python import log -import sys - -import api -#import logwatch_config as config - -class LogWatchModule (api.Module) : - name = "logs" - version = 0x0005 - - event_types = [ - "error", - "sudo", - "ssh", - "all" - ] - - def handleConnect (self) : - for source in config.sources() : - source.setModule(self) - - def error (self, msg) : - self.sendEvent("error", msg) - -def makeService (config) : - return api.makeService(LogWatchModule, config) - - diff -r e82b6df5baa3 -r b9fdb7710768 fixbot/logwatch/filters.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fixbot/logwatch/filters.py Thu Feb 04 19:40:51 2010 +0200 @@ -0,0 +1,66 @@ +import re + +class FullFilter (object) : + def __init__ (self, event_type) : + self.event_type = event_type + + def test (self, line) : + return line + +class NullFilter (object) : + def __init__ (self, pattern, flags=None) : + self.regexp = re.compile(pattern, flags) + + def test (self, line) : + match = self.regexp.search(line) + + if match : + return False + +class SimpleFilter (object) : + def __init__ (self, event_type, pattern, format) : + self.event_type = event_type + + self.regexp = re.compile(pattern) + self.format = format + + def test (self, line) : + match = self.regexp.search(line) + + if match : + return self._filter(match) + + def _filter (self, match) : + return self.format % match.groupdict() + +_timestamp = "\w{3} [0-9 ]\d \d{2}:\d{2}:\d{2}" + +all = FullFilter("all") + +all_wo_timestamps = SimpleFilter( + "all", + "^" + _timestamp + " (?P.+)$", + "%(line)s" +) + +sudo = SimpleFilter( + "sudo", + "(?P\S+)\s+sudo:\s*(?P\S+) : TTY=(?P\S+) ; PWD=(?P.+?) ; USER=(?P\S+) ; COMMAND=(?P.*)", + "%(username)s:%(tty)s - %(target_user)s@%(hostname)s:%(pwd)s - %(command)r" +) + +ssh = SimpleFilter( + "ssh", + "(?PAccepted|Failed) password for (?P\S+) from (?P\S+) port (?P\S+) (?P\S+)", + "%(success)s login for %(username)s from %(ip)s:%(port)s proto %(proto)s" +) + +cron_killer = NullFilter( + "^" + _timestamp + " \S+\s+(CRON|su)\[\d+\]: pam_unix\(cron:\w+\): session (opened|closed) for user \w+( by \(uid=\d+\))?$", + re.IGNORECASE +) + +su_nobody_killer = NullFilter( + "^" + _timestamp + " \S+\s+su\[\d+\]: (Successful su for nobody by root|\+ \?\?\? root:nobody)$", + re.IGNORECASE +) diff -r e82b6df5baa3 -r b9fdb7710768 fixbot/logwatch/logwatch.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fixbot/logwatch/logwatch.py Thu Feb 04 19:40:51 2010 +0200 @@ -0,0 +1,36 @@ +from twisted.internet import protocol, reactor +from twisted.python import log +import sys + +from fixbot import api + +class LogWatchModule (api.Module) : + name = "logs" + version = 0x0005 + + event_types = [ + "error", + "sudo", + "ssh", + "all" + ] + + def __init__ (self, config) : + """ + Initialize with logwatch_sources from config + """ + + super(LogWatchModule, self).__init__(config) + + self.sources = config['logwatch-sources'] + + def handleConnect (self) : + for source in self.sources : + source.setModule(self) + + def error (self, msg) : + self.sendEvent("error", msg) + +def makeService (config) : + return api.makeService(LogWatchModule, config) + diff -r e82b6df5baa3 -r b9fdb7710768 fixbot/logwatch/sources.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fixbot/logwatch/sources.py Thu Feb 04 19:40:51 2010 +0200 @@ -0,0 +1,105 @@ +from twisted.internet import reactor, protocol +from twisted.python import log + +from fixbot import fifo + +class LogSource (object) : + def __init__ (self, name, filters) : + # set later on + self.module = None + + # what filters to apply + self.filters = filters + + # name, for display purposes + self.name = name + + # used to gather data together into lines + self.buf = "" + + def setModule (self, module) : + self.module = module + + def handleError (self, msg) : + log.err(msg) + self.module.error(msg) + + def handleData (self, data) : + data = self.buf + data + + while "\n" in data : + line, data = data.split("\n", 1) + + self.handleLine(line) + + self.buf = data + + def handleLine (self, line) : + log.msg("Matching line `%s'..." % line) + + for filter in self.filters : + # let the filter process the line + out = filter.test(line) + + if out : + # positive match, send + log.msg("\t%s: %s" % (filter.event_type, out)) + self.module.sendEvent(filter.event_type, out) + + break + + elif out is False : + # negative match, stop processing + return + + else : # None + # no match + continue + +class File (LogSource, protocol.ProcessProtocol) : + """ + Stream lines from a regular file using /usr/bin/tail -f + """ + + def __init__ (self, name, path, filters) : + super(File, self).__init__(name, filters) + + self.path = path + + log.msg("spawning tail process for %s:%s" % (name, path)) + + reactor.spawnProcess(self, "/usr/bin/tail", ["tail", "-n0", "--follow=name", path]) + + def errReceived (self, data) : + self.handleError("tail for %s: %s" % (self.name, data)) + + def outReceived (self, data) : + self.handleData(data) + + def processEnded (self, reason) : + self.handleError("tail process for %s quit: %s" % (self.name, reason.getErrorMessage())) + +class Fifo (LogSource, fifo.Fifo) : + """ + Stream lines from a fifo object. + """ + + def __init__ (self, name, path, filters) : + LogSource.__init__(self, name, filters) + + log.msg("opening fifo for %s:%s" % (name, path)) + + fifo.Fifo.__init__(self, path) + + def dataReceived (self, data) : + self.handleData(data) + + def handleEOF (self) : + self.handleError("!!! EOF on fifo %s, re-opening" % self.name) + self.reopen() + + def connectionLost (self, reason) : + super(Fifo, self).connectionLost(reason) + self.handleError("lost fifo for %s: %s" % (self.name, reason.getErrorMessage())) + + diff -r e82b6df5baa3 -r b9fdb7710768 fixbot/logwatch_filters.py --- a/fixbot/logwatch_filters.py Thu Feb 04 19:39:37 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -import re - -class FullFilter (object) : - def __init__ (self, event_type) : - self.event_type = event_type - - def test (self, line) : - return line - -class NullFilter (object) : - def __init__ (self, pattern, flags=None) : - self.regexp = re.compile(pattern, flags) - - def test (self, line) : - match = self.regexp.search(line) - - if match : - return False - -class SimpleFilter (object) : - def __init__ (self, event_type, pattern, format) : - self.event_type = event_type - - self.regexp = re.compile(pattern) - self.format = format - - def test (self, line) : - match = self.regexp.search(line) - - if match : - return self._filter(match) - - def _filter (self, match) : - return self.format % match.groupdict() - -_timestamp = "\w{3} [0-9 ]\d \d{2}:\d{2}:\d{2}" - -all = FullFilter("all") - -all_wo_timestamps = SimpleFilter( - "all", - "^" + _timestamp + " (?P.+)$", - "%(line)s" -) - -sudo = SimpleFilter( - "sudo", - "(?P\S+)\s+sudo:\s*(?P\S+) : TTY=(?P\S+) ; PWD=(?P.+?) ; USER=(?P\S+) ; COMMAND=(?P.*)", - "%(username)s:%(tty)s - %(target_user)s@%(hostname)s:%(pwd)s - %(command)r" -) - -ssh = SimpleFilter( - "ssh", - "(?PAccepted|Failed) password for (?P\S+) from (?P\S+) port (?P\S+) (?P\S+)", - "%(success)s login for %(username)s from %(ip)s:%(port)s proto %(proto)s" -) - -cron_killer = NullFilter( - "^" + _timestamp + " \S+\s+(CRON|su)\[\d+\]: pam_unix\(cron:\w+\): session (opened|closed) for user \w+( by \(uid=\d+\))?$", - re.IGNORECASE -) - -su_nobody_killer = NullFilter( - "^" + _timestamp + " \S+\s+su\[\d+\]: (Successful su for nobody by root|\+ \?\?\? root:nobody)$", - re.IGNORECASE -) diff -r e82b6df5baa3 -r b9fdb7710768 fixbot/logwatch_sources.py --- a/fixbot/logwatch_sources.py Thu Feb 04 19:39:37 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -from twisted.internet import reactor, protocol -from twisted.python import log - -import fifo - -class LogSource (object) : - def __init__ (self, name, filters) : - # set later on - self.module = None - - # what filters to apply - self.filters = filters - - # name, for display purposes - self.name = name - - # used to gather data together into lines - self.buf = "" - - def setModule (self, module) : - self.module = module - - def handleError (self, msg) : - log.err(msg) - self.module.error(msg) - - def handleData (self, data) : - data = self.buf + data - - while "\n" in data : - line, data = data.split("\n", 1) - - self.handleLine(line) - - self.buf = data - - def handleLine (self, line) : - log.msg("Matching line `%s'..." % line) - - for filter in self.filters : - out = filter.test(line) - - if out : - log.msg("\t%s: %s" % (filter.event_type, out)) - self.module.sendEvent(filter.event_type, out) - - break - elif out is False : - return - else : # None - continue - -class File (LogSource, protocol.ProcessProtocol) : - def __init__ (self, name, path, filters) : - super(File, self).__init__(name, filters) - - self.path = path - - log.msg("spawning tail process for %s:%s" % (name, path)) - - reactor.spawnProcess(self, "/usr/bin/tail", ["tail", "-n0", "--follow=name", path]) - - def errReceived (self, data) : - self.handleError("tail for %s: %s" % (self.name, data)) - - def outReceived (self, data) : - self.handleData(data) - - def processEnded (self, reason) : - self.handleError("tail process for %s quit: %s" % (self.name, reason.getErrorMessage())) - -class Fifo (LogSource, fifo.Fifo) : - def __init__ (self, name, path, filters) : - LogSource.__init__(self, name, filters) - - log.msg("opening fifo for %s:%s" % (name, path)) - - fifo.Fifo.__init__(self, path) - - def dataReceived (self, data) : - self.handleData(data) - - def handleEOF (self) : - self.handleError("!!! EOF on fifo %s, re-opening" % self.name) - self.reopen() - - def connectionLost (self, reason) : - super(Fifo, self).connectionLost(reason) - self.handleError("lost fifo for %s: %s" % (self.name, reason.getErrorMessage())) - - diff -r e82b6df5baa3 -r b9fdb7710768 twisted/plugins/fixbot_logwatch_plugin.py --- a/twisted/plugins/fixbot_logwatch_plugin.py Thu Feb 04 19:39:37 2010 +0200 +++ b/twisted/plugins/fixbot_logwatch_plugin.py Thu Feb 04 19:40:51 2010 +0200 @@ -6,11 +6,12 @@ from twisted.application import internet -from fixbot import api, logwatch +from fixbot import api +from fixbot.logwatch import logwatch class LogwatchOptions (api.ClientOptions) : optParameters = [ - + ("logwatch-sources", None, None, "See etc/fixbot-logwatch.py"), ] optFlags = [