Bootstrap

logging模块使用TCP/UDP发送纯日志内容

logging模块使用TCP/UDP发送纯日志内容

python的logging模块允许使用多种方式(handler)记录/发送日志,包括:

  • logging
    • StreamHandler
    • FileHandler
  • logging.handlers
    • BufferingHandler
    • MemoryHandler
    • HTTPHandler
    • NTEventLogHandler
    • SMTPHandler
    • SocketHandler
    • DatagramHandler
    • SysLogHandler

常用的StreamHandler、FileHandler都好理解,将日志信息按照我们定义好的格式进行记录。但对于SocketHandler(TCP)和DatagramHandler(UDP),官方的解释为:

A handler class which writes logging records, in pickle format, to a streaming socket.

坑爹啊,我只是想发个日志而已,为什么要自作主张地把日志记录对象序列化后再以二进制形式发送?
查看SocketHandler源码,发现关键在makePickle()这个方法:

    def makePickle(self, record):
        """
        Pickles the record in binary format with a length prefix, and
        returns it ready for transmission across the socket.
        """
        ei = record.exc_info
        if ei:
            dummy = self.format(record) # just to get traceback text into record.exc_text
            record.exc_info = None  # to avoid Unpickleable error
        s = cPickle.dumps(record.__dict__, 1)
        if ei:
            record.exc_info = ei  # for next handler
        slen = struct.pack(">L", len(s))
        return slen + s

该方法从日志记录生成pickle字符串,用于发送。解决的方法很简单,继承SocketHandler和DatagramHandler,重写该方法。只对其按指定的日志格式进行格式化,而不执行pickle的操作。代码如下:

from logging.handlers import *
class MySocketHandler(SocketHandler):
    def makePickle(self, record):
        return self.format(record)+'\n'

class MyDatagramHandler(DatagramHandler):
    def makePickle(self, record):
        return self.format(record)+'\n'

此后使用MySocketHandler和MyDatagramHandler发送的就是和FileHandler记录的一样的纯日志内容了。

;