pvl/syslog/syslog.py
author Tero Marttila <terom@paivola.fi>
Tue, 19 Feb 2013 19:27:51 +0200
changeset 220 e533260bcefd
parent 173 5fc4c5e83b72
permissions -rw-r--r--
pvl-verkko: 0.4.1
"""
    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)))