如何在重新联机时将未发送的日志发送到python日志服务器?

时间:2015-04-09 16:07:46

标签: python logging python-3.4

我已经在一台计算机上成功创建了一个中央python日志记录服务器,并且可以从多个RPis登录到它。但是,当日志记录服务器关闭时,日志将丢失。有没有办法存储日志(以持久形式),直到日志服务器再次可用?

我查看了一些程序,例如graylog,sentry和logstash,但看不到任何选项。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

我已经提出了一个自定义套接字处理程序,它可以缓冲未发送的记录,直到交付。此缓冲区存储在二进制文件中,因此在程序重启或系统关闭期间会保留未发送的日志。

import os, os.path
import logging.handlers
import pickle

class BufferingSocketHandler(logging.handlers.SocketHandler):
    def __init__(self, host, port, buffer_file):
        super().__init__(host, port)
        self._buffer = FileBuffer(buffer_file)

    @property  # getter only
    def buffer(self):
        return self._buffer

    def _emit(self, record):
        try:
            s = self.makePickle(record)
            self.send(s)
            return (self.sock is not None)
        except Exception:
            self.handleError(record)
            return False

    def emit(self, record):
        self.send_buffer()
        success = self._emit(record)
        if not success:
            self.buffer.append(record)

    def send_buffer(self):
        try:
            self.acquire()
            success = True
            for item in self.buffer:
                success &= self._emit(item)
            if success:
                self.buffer.flush()
        finally:
            self.release()


class FileBuffer:
    def __init__(self, fname):
        self.fname = fname

    @property
    def size(self):
        return int(os.path.isfile(self.fname) \
                and os.path.getsize(self.fname))

    def append(self, data):
        with open(self.fname, 'ba') as f:
            pickle.dump(data, f)

    def __iter__(self):
        if self.size > 0:
            try:
                with open(self.fname, 'br') as f:
                    while True:
                        yield pickle.load(f)
            except EOFError:
                return

    def flush(self):
        if self.size > 0:
            os.remove(self.fname)

创建BufferingSocketHandler时,您必须添加一个缓冲区文件名,其中保存未传递的日志记录,直到传递。正在使用pickle序列化数据,有关详细信息,请参阅上面示例中的FileBuffer类。但是,这是一个非常简单的实现,为了提高线程安全性,您可能需要添加用于存储日志记录的数据库。

处理程序基于logging模块的SocketHandler,它的source对于理解这种修改背后的逻辑也很有意思。

使用the logging Cookbook's example,唯一需要的更改是导入此自定义处理程序并将其添加到根记录器:

import logging, logging.handlers
from custom_handlers import BufferingSocketHandler

rootLogger = logging.getLogger('')
rootLogger.setLevel(logging.DEBUG)
socketHandler = BufferingSocketHandler('localhost',
                    logging.handlers.DEFAULT_TCP_LOGGING_PORT,
                    'logging-buffer.bin')
# don't bother with a formatter, since a socket handler sends
# the event as an unformatted pickle
rootLogger.addHandler(socketHandler)

此代码仅使用 Python 3 进行测试,我不知道它是否与Python-2兼容。