zeromq是一个快速的通讯库。有好几个语言的扩展绑定。今天用它的python扩展库,为标准的logging库实现一个ZMQPUBHandler。
使用这个ZMQPUBHandler,能监听机器的某端口,然后将log信息发布(zmq.PUB)到那端口。用zeromq实现的好处是,代码实现简单,信息发布socket只是不断发送数据就行,不用理会是否有人订阅这些信息;允许多个订阅(zmq.SUB)客户连接过来,订阅的代码实现也很简单,都不需要考虑断开连接的问题。
import os , sys , types
import zmq , logging
import time

class ZMQPUBHandler( logging . Handler ):
    def __init__( self , host , port ):
        logging . Handler . __init__( self)
        ctx = zmq . Context( 1 , 1)
        self . sock = ctx . socket( zmq . PUB)
        self . sock . bind( 'tcp:// %s : %s ' %( host , port))

    def emit( self , record ):
        """
        Emit a record.

        If a formatter is specified, it is used to format the record.
        The record is then written to the stream with a trailing newline
        [N.B. this may be removed depending on feedback]. If exception
        information is present, it is formatted using
        traceback.print_exception and appended to the stream.
        """
        try :
            msg = self . format( record)
            fs = " %s \n "
            if not hasattr( types , "UnicodeType" ): #if no unicode support...
                self . sock . send( fs % msg , zmq . NOBLOCK)
            else :
                try :
                    self . sock . send( fs % msg , zmq . NOBLOCK)
                except UnicodeError :
                    self . sock . send( fs % msg . encode( "UTF-8" ), zmq . NOBLOCK)
        except ( KeyboardInterrupt , SystemExit ):
            raise
        except :
            self . handleError( record)


def main ():
    #订阅
    host = sys . argv [ 1 ]
    ctx = zmq . Context( 1 , 1)
    sock = ctx . socket( zmq . SUB)
    sock . setsockopt( zmq . SUBSCRIBE , '')
    sock . connect( 'tcp:// %s :55555' % host)

    while 1 :
        msg = sock . recv( zmq . NOBLOCK)
        if msg :
            print msg ,
        else :
            time . sleep( 0.1)

if __name__ == '__main__' :
    main()