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

How to send unsent logs to python logging server when it comes back online?

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

我查看了一些程序,例如 graylog、sentry 和 logstash,但看不到执行此操作的任何选项。

如有任何帮助,我们将不胜感激。

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

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 class。但是,这是一个非常简单的实现,为了提高线程安全性,您可能需要添加一个数据库来存储日志记录。

处理程序基于 logging 模块的 SocketHandler, it's 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)

此代码只用Python3测试过,不知道是否兼容Python-2