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

时间:2017-05-16 21:33:21

标签: python

目前我用于记录自定义日志记录系统,其工作方式如下:
我有一个Log 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,并相应地在.mssg对象上向.errLog添加消息。

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数据库。

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

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

有人有什么建议吗?

2 个答案:

答案 0 :(得分:2)

这是我的想法。使用处理程序捕获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'

答案 1 :(得分:1)

在程序开始时(在主程序中),你可以:

  • 实现您的自定义记录器=>全局变量/单身。
  • 在程序端注册一个函数,用于刷新记录器。
  • 运行您的装饰功能。

要注册功能,您可以使用MemoryHandler功能。请参阅文档中的页面Exit handlers

修改

上述想法可以简化。

要延迟记录,您可以使用页面logging.handlers — Logging handlers

中描述的标准[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 处理程序

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

用这个替换INI文件:

SQLAlchemyHandler

要登录数据库表,只需用您自己的数据库处理程序替换 alternate 处理程序。

有一些博客/ SO问题:

<强> EDIT2

注意:ORM通常支持“Eager loading”,例如SqlAlchemy