pvl.syslog: implement pvl.syslog.args.apply -> SyslogSource as in pvl.verkko-dhcp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/pvl.verkko-syslog Thu Jan 03 00:38:26 2013 +0200
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+
+"""
+ Monitor DHCP use.
+"""
+
+__version__ = '0.0'
+
+import pvl.args
+import pvl.syslog.args
+
+import logging, optparse
+
+log = logging.getLogger('main')
+
+def parse_options (argv) :
+ """
+ Parse command-line arguments.
+ """
+
+ prog = argv[0]
+
+ parser = optparse.OptionParser(
+ prog = prog,
+ usage = '%prog: [options]',
+ version = __version__,
+
+ # module docstring
+ description = __doc__,
+ )
+
+ # options
+ parser.add_option_group(pvl.args.parser(parser))
+
+ ## syslog
+ parser.add_option_group(pvl.syslog.args.parser(parser))
+
+ # defaults
+ parser.set_defaults(
+
+ )
+
+ # parse
+ options, args = parser.parse_args(argv[1:])
+
+ # apply
+ pvl.args.apply(options, prog)
+
+ return options, args
+
+def main (argv) :
+ options, args = parse_options(argv)
+
+ syslog = pvl.syslog.args.apply(options)
+
+ log.info("Start processing syslog messages...")
+
+ for item in syslog.loop() :
+ print item
+
+ # done
+ log.info("Exiting...")
+ return 0
+
+if __name__ == '__main__':
+ import sys
+
+ sys.exit(main(sys.argv))
--- a/pvl/syslog/args.py Wed Jan 02 20:46:54 2013 +0200
+++ b/pvl/syslog/args.py Thu Jan 03 00:38:26 2013 +0200
@@ -43,10 +43,17 @@
if options.syslog_fifo :
# read fifo
source = fifo.Fifo(options.syslog_fifo)
+ poll = True
+
+ elif options.syslog_tail :
+ # tail file
+ source = tail.TailFile(options.syslog_file)
+ poll = options.syslog_tail # float
elif options.syslog_file :
- # tail file
- source = tail.TailFile(options.syslog_file)
+ # read file
+ source = open(options.syslog_file)
+ poll = False
elif optional :
log.debug("No --syslog source given")
@@ -62,5 +69,7 @@
)
# build
- return SyslogSource(source, parser)
+ return SyslogSource(source, parser,
+ poll = poll
+ )
--- a/pvl/syslog/fifo.py Wed Jan 02 20:46:54 2013 +0200
+++ b/pvl/syslog/fifo.py Thu Jan 03 00:38:26 2013 +0200
@@ -38,7 +38,7 @@
def _open (self) :
"""
- Open the internal fd.
+ Open the internal fd (nonblocking).
"""
assert self._fd is None
--- a/pvl/syslog/parser.py Wed Jan 02 20:46:54 2013 +0200
+++ b/pvl/syslog/parser.py Thu Jan 03 00:38:26 2013 +0200
@@ -148,5 +148,5 @@
if self.filter(line, item) :
yield item
+ __call__ = process
-
--- a/pvl/syslog/syslog.py Wed Jan 02 20:46:54 2013 +0200
+++ b/pvl/syslog/syslog.py Thu Jan 03 00:38:26 2013 +0200
@@ -2,6 +2,8 @@
Syslog handling.
"""
+import select
+
import logging; log = logging.getLogger('pvl.syslog.source')
class SyslogSource (object) :
@@ -9,16 +11,22 @@
A source of syslog items.
"""
- def __init__ (self, source, parser) :
+ def __init__ (self, source, parser, poll=None) :
"""
Using given underlying line source.
+
+ source - file-like object with poll() and iter()
+ parser - process() bytes -> messages
+ poll - using given polling style:
+ True - select() source
+ float - given interval
+ None/False - single-shot
"""
self.source = source
self.parser = parser
- # proxy
- self.poll = source.poll
+ self._poll = poll
def __iter__ (self) :
"""
@@ -26,6 +34,77 @@
"""
# directly iter across source
- for item in self.parser.process(self.source) :
+ for item in self.parser(self.source) :
yield item
+
+ def poll (self, timeout=None) :
+ """
+ Poll source for input, with given timeout in seconds (float).
+
+ A timeout of None indicates to block forever, False indicates to never block.
+
+ Returns True if we have input waiting, False on timeout with no input. None on indeterminate.
+ """
+
+ read = write = ()
+
+ if timeout is True :
+ timeout = None
+ read += (self.source, )
+
+ elif timeout is False :
+ timeout = 0.0
+
+ log.debug("%f", timeout)
+
+ # select
+ read, write, ex = select.select(read, write, [], timeout)
+
+ if read :
+ return True
+
+ else :
+ # timeout
+ return False
+
+ def loop (self) :
+ """
+ Continuously read items from syslog source, blocking as suitable.
+
+ Returns once no more lines are available.
+
+ XXX: reconnect?
+ """
+
+ # mainloop
+ while True :
+ # pull in messages
+ for item in self :
+ yield item
+ # poll
+ if self._poll :
+ # wait
+ self.poll(self._poll)
+ else :
+ # done
+ break
+
+ log.debug("tick")
+
+ log.debug("exit")
+
+ def stop (self) :
+ """
+ Stop loop after current iteration.
+ """
+
+ self._poll = False
+
+ def main (self) :
+ """
+ Mainloop.
+ """
+
+ # TODO: SIGINT -> stop()
+ return loop()