|
1 from twisted.internet import reactor, protocol |
|
2 from twisted.python import log |
|
3 |
|
4 from fixbot import fifo |
|
5 |
|
6 class LogSource (object) : |
|
7 def __init__ (self, name, filters) : |
|
8 # set later on |
|
9 self.module = None |
|
10 |
|
11 # what filters to apply |
|
12 self.filters = filters |
|
13 |
|
14 # name, for display purposes |
|
15 self.name = name |
|
16 |
|
17 # used to gather data together into lines |
|
18 self.buf = "" |
|
19 |
|
20 def setModule (self, module) : |
|
21 self.module = module |
|
22 |
|
23 def handleError (self, msg) : |
|
24 log.err(msg) |
|
25 self.module.error(msg) |
|
26 |
|
27 def handleData (self, data) : |
|
28 data = self.buf + data |
|
29 |
|
30 while "\n" in data : |
|
31 line, data = data.split("\n", 1) |
|
32 |
|
33 self.handleLine(line) |
|
34 |
|
35 self.buf = data |
|
36 |
|
37 def handleLine (self, line) : |
|
38 log.msg("Matching line `%s'..." % line) |
|
39 |
|
40 for filter in self.filters : |
|
41 # let the filter process the line |
|
42 out = filter.test(line) |
|
43 |
|
44 if out : |
|
45 # positive match, send |
|
46 log.msg("\t%s: %s" % (filter.event_type, out)) |
|
47 self.module.sendEvent(filter.event_type, out) |
|
48 |
|
49 break |
|
50 |
|
51 elif out is False : |
|
52 # negative match, stop processing |
|
53 return |
|
54 |
|
55 else : # None |
|
56 # no match |
|
57 continue |
|
58 |
|
59 class File (LogSource, protocol.ProcessProtocol) : |
|
60 """ |
|
61 Stream lines from a regular file using /usr/bin/tail -f |
|
62 """ |
|
63 |
|
64 def __init__ (self, name, path, filters) : |
|
65 super(File, self).__init__(name, filters) |
|
66 |
|
67 self.path = path |
|
68 |
|
69 log.msg("spawning tail process for %s:%s" % (name, path)) |
|
70 |
|
71 reactor.spawnProcess(self, "/usr/bin/tail", ["tail", "-n0", "--follow=name", path]) |
|
72 |
|
73 def errReceived (self, data) : |
|
74 self.handleError("tail for %s: %s" % (self.name, data)) |
|
75 |
|
76 def outReceived (self, data) : |
|
77 self.handleData(data) |
|
78 |
|
79 def processEnded (self, reason) : |
|
80 self.handleError("tail process for %s quit: %s" % (self.name, reason.getErrorMessage())) |
|
81 |
|
82 class Fifo (LogSource, fifo.Fifo) : |
|
83 """ |
|
84 Stream lines from a fifo object. |
|
85 """ |
|
86 |
|
87 def __init__ (self, name, path, filters) : |
|
88 LogSource.__init__(self, name, filters) |
|
89 |
|
90 log.msg("opening fifo for %s:%s" % (name, path)) |
|
91 |
|
92 fifo.Fifo.__init__(self, path) |
|
93 |
|
94 def dataReceived (self, data) : |
|
95 self.handleData(data) |
|
96 |
|
97 def handleEOF (self) : |
|
98 self.handleError("!!! EOF on fifo %s, re-opening" % self.name) |
|
99 self.reopen() |
|
100 |
|
101 def connectionLost (self, reason) : |
|
102 super(Fifo, self).connectionLost(reason) |
|
103 self.handleError("lost fifo for %s: %s" % (self.name, reason.getErrorMessage())) |
|
104 |
|
105 |