如何在Python中使用msgpack而不是pickle来记录SocketHandler?

时间:2013-07-15 08:35:12

标签: python logging pickle msgpack

Logging Cookbook描述了一种在远程日志服务器上使用Python日志记录功能的方法。

不幸的是,此实现需要公开服务器,该服务器使用 unPickle 函数处理接收的数据,该函数是severe security risk

我想使用msgpack库传递日志消息而不是pickle模块。是否有基于日志记录 msgpack 的现成可用解决方案? 在自己实施时是否有任何特殊的预防措施需要考虑?

更新 我已经设法修改了Logging Cookbook中的原始示例,并获得了似乎有用的东西。

日志服务器:

import logging
import logging.handlers
import SocketServer
import struct
import msgpack

class LogRecordStreamHandler(SocketServer.StreamRequestHandler):
    """Handler for a streaming logging request.

    This basically logs the record using whatever logging policy is
    configured locally.
    """

    def handle(self):
        """
        Handle multiple requests - each expected to be a 4-byte length,
        followed by the LogRecord in pickle format. Logs the record
        according to whatever policy is configured locally.
        """
        import msgpack as p
        unp=p.Unpacker()
        while True:
            r=self.request.recv(1000)
            if len(r)==0:
                break
            unp.feed(r)
            for obj in unp:
                record = logging.makeLogRecord(obj)
                self.handleLogRecord(record)


    def handleLogRecord(self, record):
        # if a name is specified, we use the named logger rather than the one
        # implied by the record.
        if self.server.logname is not None:
            name = self.server.logname
        else:
            name = record.name
        logger = logging.getLogger(name)
        # N.B. EVERY record gets logged. This is because Logger.handle
        # is normally called AFTER logger-level filtering. If you want
        # to do filtering, do it at the client end to save wasting
        # cycles and network bandwidth!
        logger.handle(record)

class LogRecordSocketReceiver(SocketServer.ThreadingTCPServer):
    """
    Simple TCP socket-based logging receiver suitable for testing.
    """

    allow_reuse_address = 1

    def __init__(self, host='localhost',
                 port=65432,
                 handler=LogRecordStreamHandler):
        SocketServer.ThreadingTCPServer.__init__(self, (host, port), handler)
        self.abort = 0
        self.timeout = 1
        self.logname = None

    def serve_until_stopped(self):
        import select
        abort = 0
        while not abort:
            rd, wr, ex = select.select([self.socket.fileno()],
                                       [], [],
                                       self.timeout)
            if rd:
                self.handle_request()
            abort = self.abort

def main():
    logging.basicConfig(
        format='%(relativeCreated)5d %(name)-15s %(levelname)-8s %(message)s')
    tcpserver = LogRecordSocketReceiver()
    print('About to start TCP server...')
    tcpserver.serve_until_stopped()

if __name__ == '__main__':
    main()

示例客户端:

import logging, logging.handlers
import msgpack
import test1
#import auxiliary_module

class MsgpackHandler(logging.handlers.SocketHandler):
  def __init__(self, host, port):
     logging.handlers.SocketHandler.__init__(self,host,port)
  def makePickle(self,record):
     #Use msgpack instead of pickle, for increased safety
     return msgpack.packb(record.__dict__)
# create logger with 'spam_application'
logger = logging.getLogger('my_log')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
#fh = logging.FileHandler('spam.log')
fh=MsgpackHandler('localhost',65432)
fh.setLevel(logging.DEBUG)
# create formatter and add it to the handler
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(fh)

logger.info('this is sample info message')
logger.error('this is sample error message')

0 个答案:

没有答案