terom@3: from twisted.internet import protocol, reactor terom@3: from twisted.python import log terom@3: import sys, re terom@3: terom@3: import api terom@3: terom@3: class TailProcessProtocol (protocol.ProcessProtocol) : terom@3: def __init__ (self, module, name, filters) : terom@3: self.module = module terom@3: self.name = name terom@3: self.filters = filters terom@3: terom@3: self.buf = "" terom@3: terom@3: def errReceived (self, data) : terom@3: self.module.error("tail for %s: %s" % (self.name, data)) terom@3: terom@3: def outReceived (self, data) : terom@4: data = self.buf + data terom@3: terom@3: while "\n" in data : terom@3: line, data = data.split("\n", 1) terom@4: terom@4: log.msg("Matching line `%s'..." % line) terom@3: terom@3: for filter in self.filters : terom@3: out = filter.test(line) terom@3: terom@4: if out : terom@4: log.msg("\t%s: %s" % (filter.event_type, out)) terom@4: self.module.sendEvent(filter.event_type, out) terom@4: terom@3: self.buf = data terom@3: terom@4: def processEnded (self, reason) : terom@4: msg = "tail process for %s quit: %s" % (self.name, reason.getErrorMessage()) terom@4: terom@4: log.err(msg) terom@4: self.module.error(msg) terom@4: terom@3: class Filter (object) : terom@3: def __init__ (self, regexp, event_type) : terom@3: self.regexp = re.compile(regexp) terom@3: self.event_type = event_type terom@3: terom@3: def test (self, line) : terom@3: match = self.regexp.search(line) terom@3: terom@3: if match : terom@3: return self._filter(match) terom@3: terom@3: def _filter (self, match) : terom@3: return match.string terom@3: terom@6: class AutoFilter (Filter) : terom@6: # your event type here, as a string terom@6: EVENT = None terom@4: terom@6: # your regexp here, with named matchgroups terom@6: REGEXP = None terom@6: terom@6: # your output format, with named interpolation params terom@6: OUTPUT = None terom@6: terom@3: def __init__ (self) : terom@6: super(AutoFilter, self).__init__(self.REGEXP, self.EVENT) terom@6: terom@6: def _filter (self, match) : terom@6: return self.OUTPUT % match.groupdict() terom@3: terom@6: class SudoFilter (AutoFilter) : terom@6: EVENT = "sudo" terom@6: REGEXP = "sudo:\s*(?P\S+) : TTY=(?P\S+) ; PWD=(?P.+?) ; USER=(?P\S+) ; COMMAND=(?P.*)" terom@6: OUTPUT = "%(username)s:%(tty)s - %(pwd)s - `%(command)s` as %(target_user)s" terom@6: terom@6: class SSHFilter (AutoFilter) : terom@6: EVENT = "ssh" terom@6: REGEXP = "(?PAccepted|Failed) password for (?P\S+) from (?P\S+) port (?P\S+) (?P\S+)" terom@6: OUTPUT = "%(success)s login for %(username)s from %(ip)s:%(port)s proto %(proto)s" terom@3: terom@3: class ExampleModule (api.Module) : terom@3: name = "logs" terom@3: version = 0x0001 terom@3: terom@3: event_types = [ terom@3: "error", terom@6: "sudo", terom@6: "ssh", terom@3: ] terom@3: terom@3: log_files = ( terom@3: ("auth.log", "/var/log/auth.log", ( terom@3: SudoFilter(), terom@6: SSHFilter(), terom@3: )), terom@3: ) terom@3: terom@3: log_objs = None terom@3: terom@3: def handleConnect (self) : terom@3: log.msg("Spawning tail processes...") terom@3: terom@3: self.log_objs = dict() terom@3: terom@3: for name, file, filters in self.log_files : terom@4: log.msg("\t%s - %s..." % (name, file)) terom@3: terom@4: p = self.log_objs[name] = TailProcessProtocol(self, name, filters) terom@3: terom@6: reactor.spawnProcess(p, "/usr/bin/tail", ["tail", "-n0", "--follow=name", file]) terom@3: terom@3: def error (self, msg) : terom@3: self.sendEvent("error", msg) terom@3: terom@3: if __name__ == '__main__' : terom@6: ExampleModule().run() terom@3: