Pythonic将特定事物记录到文件的方法?

时间:2009-07-06 21:18:58

标签: python logging

据我所知,Python记录器不能直接实例化,因为文档建议:

  

请注意,记录器永远不会   直接实例化,但始终   通过模块级功能   logging.getLogger(name)

..这是合理的,因为你需要为每个类/模块创建记录器对象,因为有better alternative

但是,在某些情况下,我希望创建一个记录器对象,并将一个文件专门附加到它,以便将某些特定于应用程序的输出记录到该文件中;然后关闭日志文件。

例如,我有一个程序可以在PyPI中构建所有包。所以基本上假设每个包都有一个for循环。在循环内部,我想“创建”一个记录器,附加一个文件处理程序(例如:/var/logs/pypi/django/20090302_1324.build.log并发送python setup.py build的输出(以及其他内容)这个日志文件。一旦完成,我想关闭/销毁记录器,continue以类似的方式构建其他包。

所以你看到..调用logging.getLogger的正常Pythonic方式在这里不适用。需要创建临时记录器对象。

目前,我通过将文件名本身作为记录器名称传递来实现此目的:

>>> packagelog = logging.getLogger('/var/..../..34.log')
>>> # attach handler, etc..

我想问......有更好的方法吗?

3 个答案:

答案 0 :(得分:4)

您可以使用一个记录器和多个处理程序,而不是许多记录器。例如:

log = logging.getLogger(name)
while some_condition:
    try:
        handler = make_handler(filename)
        log.addHandler(handler)
        # do something and log

    finally:
        log.removeHandler(handler)
        handler.close()

答案 1 :(得分:1)

这里有两个问题:

  1. 能够在流程的不同阶段将输出定向到不同的日志文件。
  2. 能够将任意命令的stdout / stderr重定向到那些相同的日志文件。
  3. 对于第1点,我会同意ars的答案:他只关注使用多个处理程序和一个记录器。他的格式有点混乱,所以我将在下面重申:

    logger = logging.getLogger("pypibuild")
    now_as_string = datetime.datetime.utcnow().strftime("%Y%m%d_%H%M")
    for package in get_pypi_packages():
        fn = '/var/logs/pypi/%s/%s.log' % (package, now_as_string)
        h = logging.FileHandler(fn, 'w')
        logger.addHandler(h)
        perform_build(package)
        logger.removeHandler(h)
        h.close()
    

    关于第2点,perform_build()步骤,为简单起见,我假设我们不需要担心多核环境。然后,subprocess模块就是你的朋友。在下面的代码片段中,我省略了错误处理,花哨格式化和其他一些细节,但它应该给你一个公平的想法。

    def perform_build(package):
        logger.debug("Starting build for package %r", package)
        command_line = compute_command_line_for_package(package)
        process = subprocess.Popen(command_line, shell=True,
                                   stdin=PIPE, stdout=PIPE, stderr=PIPE)
        stdout, stderr = process.communicate()
        logger.debug("Build stdout contents: %r", stdout)
        logger.debug("Build stderr contents: %r", stderr)
        logger.debug("Finished build for package %r", package)
    

    就是这样。

答案 2 :(得分:0)

假设你正在调用setup.py build作为子进程,我认为你真的只想要输出重定向,你可以通过子进程调用获得它。

from subprocess import Popen
with open('/var/logs/pypi/django/%s.build.log' % time_str, 'w') as fh:
    Popen('python setup.py build'.split(), stdout=fh, stderr=fh).communicate()

如果您将setup.py build作为Python子例程调用(即导入该模块并调用它的主例程),那么您可以尝试将另一个logging.HandlerFileHandler)添加到记录器如果存在这样的记录器,则在该模块中。

<强>更新

根据回答评论,听起来您只想add a new FileHandler到当前模块的记录器,然后将其记录到那个,然后remove it from the logger later on。这更像是你在寻找什么?