"""
Syslog handling.
XXX: this belongs in pvl.syslog.source (apart from __iter__?)
"""
import select
import logging; log = logging.getLogger('pvl.syslog.source')
class SyslogSource (object) :
"""
Process syslog input from a given source.
Implements an iterable mainloop doing continuous polling on the source, using either a timeout or
select():able source.
"""
def __init__ (self, source, parser, filter, poll=None) :
"""
Using given underlying line source.
source - source to select() if poll=True
poll - polling behaviour for source
"""
self.source = source
self.parser = parser
self.filter = filter
self.poll = poll
def __iter__ (self) :
"""
Yield available input.
Raises EOFError if source has been closed.
"""
return self.filter(self.parser(self.source))
def fileno (self) :
return self.source.fileno()
def select (self, poll=None, reading=(), writing=()) :
"""
Poll our source for input, with given polling behaviour:
True - select() on source
False - peek on source
float - timeout in seconds
Returns None on unknown, empty sequence on timeout, list of readables on select.
"""
if poll is True :
timeout = None # block
reading += (self, ) # source.fileno()
elif not poll :
timeout = 0.0 # do not block
else :
timeout = float(poll)
log.debug("%s (%s)", reading, timeout)
# select
readable, writeable, ex = select.select(reading, writing, [], timeout)
log.debug("select: %s", readable)
if readable :
return readable
elif reading :
# timeout
# XXX: this is the same as readable
return ()
else :
# unknown
return None
def main (self, poll=None) :
"""
Yield active syslog sources, polling as given.
Returns once no more lines are available.
XXX: reconnect? or source takes care of that..
TODO: SIGINT -> finish iteration and return?
"""
# from __init__
# note that we must interpret poll here, since False -> never poll
if poll is None :
poll = self.poll
# mainloop
while True :
# caller is responsible for reading them!
yield self
# poll
if poll :
# wait
self.select(poll)
else :
# done
break
log.debug("exit")
def close (self) :
"""
Close the syslog source, if possible.
"""
# XXX: do all sources support close?
self.source.close()
def __str__ (self) :
return ' | '.join((str(self.source), str(self.parser), str(self.filter)))