6 |
6 |
7 import logging; log = logging.getLogger('pvl.syslog.source') |
7 import logging; log = logging.getLogger('pvl.syslog.source') |
8 |
8 |
9 class SyslogSource (object) : |
9 class SyslogSource (object) : |
10 """ |
10 """ |
11 A source of syslog items. |
11 Process syslog input from a given source. |
|
12 |
|
13 Implements an iterable mainloop doing continuous polling on the source, using either a timeout or |
|
14 select():able source. |
12 """ |
15 """ |
13 |
16 |
14 def __init__ (self, source, parser, filter=None, poll=None) : |
17 def __init__ (self, syslog, source, poll=None) : |
15 """ |
18 """ |
16 Using given underlying line source. |
19 Using given underlying line source. |
17 |
20 |
18 source - file-like object with poll() and iter() |
21 syslog - iterable |
19 parser - process() bytes -> items |
22 source - source to select() if poll=True |
20 filter - filter items |
23 poll - polling behaviour |
21 poll - using given polling style: |
|
22 True - select() source |
|
23 float - given interval |
|
24 None/False - single-shot |
|
25 """ |
24 """ |
26 |
25 |
|
26 self.syslog = syslog |
27 self.source = source |
27 self.source = source |
28 self.parser = parser |
|
29 self.filter = filter |
|
30 |
|
31 log.debug("source: %s", source) |
|
32 |
|
33 self._poll = poll |
28 self._poll = poll |
34 |
29 |
35 def __iter__ (self) : |
30 def poll (self, poll=None) : |
36 """ |
31 """ |
37 Read syslog messages from source. |
32 Poll our source for input, with given polling behaviour: |
38 """ |
33 True - select() on source |
39 |
34 False - peek on source |
40 # directly iter across source |
35 float - timeout in seconds |
41 iter = self.source |
|
42 |
|
43 # parse |
|
44 iter = self.parser(iter) |
|
45 |
|
46 # filter ? |
|
47 if self.filter : |
|
48 iter = self.filter(iter) |
|
49 |
|
50 return iter |
|
51 |
|
52 def poll (self, timeout=None) : |
|
53 """ |
|
54 Poll source for input, with given timeout in seconds (float). |
|
55 |
|
56 A timeout of None indicates to block forever, False indicates to never block. |
|
57 |
36 |
58 Returns True if we have input waiting, False on timeout with no input. None on indeterminate. |
37 Returns True if we have input waiting, False on timeout with no input. None on indeterminate. |
59 """ |
38 """ |
60 |
39 |
61 read = write = () |
40 reading = writing = () |
62 |
41 |
63 if timeout is True : |
42 if poll is True : |
64 timeout = None |
43 timeout = None # block |
65 read += (self.source, ) |
44 reading += (self.source, ) # file-like object with fileno() |
66 |
45 |
67 elif timeout is False : |
46 elif not poll : |
68 timeout = 0.0 |
47 timeout = 0.0 # do not block |
|
48 |
|
49 else : |
|
50 timeout = float(poll) |
69 |
51 |
70 log.debug("%s", timeout) |
52 log.debug("%s", timeout) |
71 |
53 |
72 # select |
54 # select |
73 read, write, ex = select.select(read, write, [], timeout) |
55 readable, writeable, ex = select.select(reading, writing, [], timeout) |
74 |
56 |
75 if read : |
57 if readable : |
76 return True |
58 return True |
77 |
59 |
78 else : |
60 elif reading : |
79 # timeout |
61 # timeout |
80 return False |
62 return False |
81 |
63 |
82 def loop (self) : |
64 else : |
|
65 # unknown |
|
66 return None |
|
67 |
|
68 def main (self, poll=None) : |
83 """ |
69 """ |
84 Continuously read items from syslog source, blocking as suitable. |
70 yield items from syslog source, polling as given. |
85 |
71 |
86 Returns once no more lines are available. |
72 Returns once no more lines are available. |
87 |
73 |
88 XXX: reconnect? |
74 XXX: reconnect? or source takes care of that.. |
|
75 TODO: SIGINT -> finish iteration and return? |
89 """ |
76 """ |
|
77 |
|
78 if poll is None : |
|
79 poll = self._poll |
90 |
80 |
91 # mainloop |
81 # mainloop |
92 while True : |
82 while True : |
93 log.debug("tick") |
|
94 |
|
95 # pull in messages |
83 # pull in messages |
96 for item in self : |
84 for item in self.syslog : |
97 log.debug("%s", item) |
85 log.debug("%s", item) |
98 yield item |
86 yield item |
99 |
87 |
100 # poll |
88 # poll |
101 if self._poll : |
89 if poll : |
102 # wait |
90 # wait |
103 self.poll(self._poll) |
91 self.poll(poll) |
104 else : |
92 else : |
105 # done |
93 # done |
106 break |
94 break |
107 |
95 |
108 log.debug("exit") |
96 log.debug("exit") |
109 |
|
110 def stop (self) : |
|
111 """ |
|
112 Stop loop after current iteration. |
|
113 """ |
|
114 |
97 |
115 self._poll = False |
98 __iter__ = main |
116 |
|
117 def main (self) : |
|
118 """ |
|
119 Mainloop. |
|
120 """ |
|
121 |
|
122 # TODO: SIGINT -> stop() |
|
123 return loop() |
|