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

Python:仅在脚本运行结束时刷新日志记录,python,Python,目前,我使用一个自定义日志系统记录日志,其工作方式如下: 我有一个日志类,其中包含以下内容: class Log: def __init__(self): self.script = "" self.datetime = datetime.datetime.now().replace(second=0, microsecond=0) self.mssg = "" self.mssg_detail = "" s

目前,我使用一个自定义日志系统记录日志,其工作方式如下:
我有一个日志
,其中包含以下内容:

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 
因此,脚本通常是由多个按顺序运行的方法组成的类。 因此,我运行这些方法(如上面提到的),最后我将日志对象上传到mysql数据库中


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

我不喜欢该模块的地方在于,它不可能将消息“保存”到一个日志对象上,以便仅在运行结束时上载/保存到日志。相反,每次日志调用都会将消息写入/发送到文件等,这有时会造成许多性能问题。我可以使用
处理程序。MemoryHandler
,但它的性能似乎仍然不如我原来的系统:据说它会定期收集消息并将它们刷新到另一个处理程序——这不是我想要的:我想在内存中收集消息,并在请求时使用显式函数刷新它们

有人有什么建议吗?

在程序开始时(主要),您可以:

  • 实例化自定义记录器=>全局变量/单例
  • 在程序末尾注册一个函数,该函数将刷新记录器
  • 运行您的装饰功能
要注册函数,可以使用
atexit.register
函数。请参阅文档中的页面

编辑

上述想法可以简化

要延迟日志记录,您可以使用页面中描述的标准
MemoryHandler
处理程序

看看这个GitHub项目:

并将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
要登录到数据库表,只需用您自己的数据库处理程序替换替代的处理程序

关于这一点,有一些blog/SO问题:

  • 您可以查看以创建
    SQLAlchemyHandler
  • 看看您是否正在使用DJango
EDIT2


注意:ORM通常支持“即时加载”,例如使用

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

顺便说一句,你应该在你的装饰程序中重新激活这个异常。@Laurent LAPORTE不,关键是脚本要一直持续到最后才能上传日志……这是你的选择,但不是一个好的做法。例如,如何处理
键盘中断?“但现在我想修改这些项,使它们与python的“官方”日志模块集成。”你是什么意思?为什么这样做?我的意思是,decorator方法中的表达式
self.logger.err+=fun.\u name.\u+”:error:“+str(e.args)
等将替换为
logging.error(fun.\u name.\u+”:error:“+str(e.args))
。类似地,
Log
类声明将替换为basicConfig日志声明。我这样做是因为我需要将我的代码与另一个使用主要python日志模块的库集成!它没有回答我的帖子的主要问题(即我想摆脱我的自定义记录器并用python日志实用程序替换它),但它绝对是我可以用来改进代码的东西。如果你使用数据库,你肯定有一个可以配置的缓存。你可以在标准记录器上使用它。@LaurentPorte我刚才给出了一个回答,回答了具体的问题。但当然,更明显的答案是,您可以编写一个直接进入数据库的处理程序。我想底线是。。。编写一个处理程序来完成您想要的任务。@LaurentPorte Ok thx。我已经在我的第一篇文章中提到了
memoryhandler
。问题是,缓冲区已满或发生具有指定严重级别的事件时(根据文档),它们会被刷新。这些选项都不让我满意,我也不知道如何循环使用它们。我想能够上传所有日志到数据库显式调用函数这样做。顺便问一下,你认为我可以用吗?只需丢弃所有实际日志事件,然后在退出时上载所有日志记录?您可以使用大小非常大的
MemoryHandler
…是的,您可以使用
LogRecord
对象:它是一个简单的平面结构。thx很多。我想知道-或者那些日志记录的东西,我可以用它来代替stringio?我还没有研究过。很抱歉