我已经在一台计算机上成功创建了一个中央python日志记录服务器,并且可以从多个RPis登录到它。但是,当日志记录服务器关闭时,日志将丢失。有没有办法存储日志(以持久形式),直到日志服务器再次可用?
我查看了一些程序,例如graylog,sentry和logstash,但看不到任何选项。
非常感谢任何帮助。
答案 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兼容。