Python:仅在脚本运行结束时刷新日志记录



目前我用于记录一个自定义日志记录系统,其工作原理如下:
我有一个类似于以下内容的日志class

class Log:
def __init__(self):
self.script = ""
self.datetime = datetime.datetime.now().replace(second=0, microsecond=0)
self.mssg = ""
self.mssg_detail = ""
self.err = ""
self.err_detail = ""

我创建了一个函数装饰器,用于对函数调用执行try/except,并相应地向Log对象添加.mssg.err消息。

def logging(fun):
@functools.wraps(fun)
def inner(self, *args):
try:
f = fun(self, *args)
self.logger.mssg += fun.__name__ +" :ok, "                
return f               
except Exception as e:
self.logger.err += fun.__name__ +": error: "+str(e.args) 
return inner 

因此,脚本通常是一个由多个按顺序运行的方法组成的类。 因此,我运行了这些方法(如上所述),最后我将 Log 对象上传到 mysql db。

这工作得很好,很好。但是现在我想修改这些项目,以便它们与python的"官方"日志记录模块集成。

我不喜欢该模块的是,不可能将消息"保存"到 1 个日志对象上,以便仅在运行结束时上传/保存到日志。相反,每个日志记录调用都会将消息写入/发送到文件等 - 这有时会产生很多性能问题。我可以使用handlers.MemoryHandler,但它似乎仍然不能像我的原始系统那样执行:据说可以收集消息并定期将它们刷新到另一个处理程序 - 这不是我想要的:我想收集内存中的消息并根据请求使用显式函数刷新它们。

有人有什么建议吗?

这是我的想法。使用处理程序捕获 StringIO 中的日志。然后,您可以随时获取StringIO。由于讨论线程中可能存在一些混淆 - StringIO 是字符串的"类似文件"的接口,因此从未涉及实际文件。

import logging
import io
def initialize_logging(log_level, log_name='default_logname'):
logger = logging.getLogger(log_name)
logger.setLevel(log_level)
log_stream = io.StringIO()
if not logger.handlers:
ch = logging.StreamHandler(log_stream)
ch.setLevel(log_level)
ch.setFormatter(logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
))
logger.addHandler(ch)
logger.propagate = 0
return logger, log_stream

然后像这样:

>>> logger, log_stream = initialize_logging(logging.INFO, "logname")
>>> logger.warning("Hello World!")

当您需要日志信息时:

>>> log_stream.getvalue()
'2017-05-16 16:35:03,501 - logname - WARNING - Hello World!n'

在程序启动时(主要),您可以:

  • 实例化自定义记录器 =>全局变量/单例。
  • 在程序端注册一个函数,该函数将刷新您的记录器。
  • 运行修饰的函数。

要注册函数,您可以使用atexit.register函数。请参阅文档中的退出处理程序页面。

编辑

上述想法可以简化。

要延迟日志记录,您可以使用标准MemoryHandler处理程序,如页面中所述 logging.handlers — 日志记录处理程序

看看这个 GitHub 项目:https://github.com/tantale/python-ini-cfg-demo

并将 INI 文件替换为以下内容:

[formatters]
keys=default
[formatter_default]
format=%(asctime)s:%(levelname)s:%(message)s
class=logging.Formatter
[handlers]
keys=console, alternate
[handler_console]
class=logging.handlers.MemoryHandler
formatter=default
args=(1024, INFO)
target=alternate
[handler_alternate]
class=logging.StreamHandler
formatter=default
args=()
[loggers]
keys=root
[logger_root]
level=DEBUG
formatter=default
handlers=console

要记录到数据库表,只需将备用处理程序替换为您自己的数据库处理程序即可。

有一些关于此的博客/SO问题:

  • 您可以查看将异常记录到 SQLAlchemy 数据库以创建SQLAlchemyHandler
  • 如果你使用的是DJango,请参阅将Django日志存储到数据库。

编辑2

注意:ORM通常支持"Eager Load",例如使用SqlAlchemy

最新更新