【问题标题】:Using program variables in python logging configuration file在 python 日志记录配置文件中使用程序变量
【发布时间】:2015-11-15 17:10:17
【问题描述】:

我正在尝试使用以下命令启用我的 python 日志记录:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
import logging.config
import os
test_filename = 'my_log_file.txt'
try:
    logging.config.fileConfig('loggingpy.conf', disable_existing_loggers=False)
except Exception as e:
    # try to set up a default logger
    logging.error("No loggingpy.conf to parse", exc_info=e)
    logging.basicConfig(level=logging.WARNING, format="%(asctime)-15s %(message)s")
test1_log = logging.getLogger("test1")
test1_log.critical("test1_log crit")
test1_log.error("test1_log error")
test1_log.warning("test1_log warning")
test1_log.info("test1_log info")
test1_log.debug("test1_log debug")

我想使用 loggingpy.conf 文件来控制日志记录,如下所示:

[loggers]
keys=root

[handlers]
keys=handRoot

[formatters]
keys=formRoot

[logger_root]
level=INFO
handlers=handRoot

[handler_handRoot]
class=FileHandler
level=INFO
formatter=formRoot
args=(test_filename,)

[formatter_formRoot]
format=%(asctime)s:%(name)s:%(process)d:%(lineno)d %(levelname)s %(message)s
datefmt=
class=logging.Formatter

在这里,我试图将日志记录路由到由本地“test_filename”命名的文件。当我运行它时,我得到:

ERROR:root:No loggingpy.conf to parse
Traceback (most recent call last):
  File "logging_test.py", line 8, in <module>
    logging.config.fileConfig('loggingpy.conf', disable_existing_loggers=False)
  File "/usr/lib/python2.7/logging/config.py", line 85, in fileConfig
    handlers = _install_handlers(cp, formatters)
  File "/usr/lib/python2.7/logging/config.py", line 162, in _install_handlers
    args = eval(args, vars(logging))
  File "<string>", line 1, in <module>
NameError: name 'test_filename' is not defined
CRITICAL:test1:test1_log crit
ERROR:test1:test1_log error
WARNING:test1:test1_log warning

阅读docs,似乎配置中的“args”值是在日志包命名空间的上下文中评估的,而不是在调用 fileConfig 时的上下文。是否有任何体面的方法可以尝试通过配置文件使日志记录以这种方式运行,以便我可以配置动态日志文件名(通常像“InputFile.log”),但仍然可以灵活地使用日志记录配置文件进行更改吗?

【问题讨论】:

  • 我误读了这个问题,因此删除了我的(严重错误的)评论。

标签: python python-2.7 logging


【解决方案1】:

尽管这是一个老问题,但我认为这仍然具有相关性。上述解决方案的替代方法是使用logging.config.dictConfig(...) 并操作字典。

MWE:

log_config.yml

version: 1
disable_existing_loggers: false
formatters:
  default:
    format: "%(asctime)s:%(name)s:%(process)d:%(lineno)d %(levelname)s %(message)s"
handlers:
  console:
    class: logging.StreamHandler
    formatter: default
    stream: ext://sys.stdout
    level: DEBUG
  file:
    class: logging.FileHandler
    formatter: default
    filename: "{path}/service.log"
    level: DEBUG
root:
  level: DEBUG
  handlers:
  - file
  - console

example.py

import logging.config
import sys
import yaml

log_output_path = sys.argv[1]

log_config = yaml.load(open("log_config.yml"))
log_config["handlers"]["file"]["filename"] = log_config["handlers"]["file"]["filename"].format(path = log_output_path)
logging.config.dictConfig(log_config)

logging.debug("test")

可执行如下:

python example.py .

结果:

  • 当前工作目录中的service.log 文件包含一行日志消息。
  • 控制台输出一行日志消息。

两者都声明如下:
2016-06-06 20:56:56,450:root:12232:11 DEBUG test

【讨论】:

  • 我喜欢这个。这是干净的,不会破坏命名空间。
  • 如果我没记错的话,这需要密钥(handlers/file/filename)存在。如果不是,这将失败并出现异常。您脚本的每个用户都应该知道,如果他们重命名文件处理程序或想要完全摆脱它等,此脚本将会失败。
  • 你是对的,如果有没有在所有地方正确反映的更改,脚本就会失败。这就是为什么我将其标记为 MWE。它不打算在产品中复制和使用,但应该显示给定问题的可能解决方案。
【解决方案2】:

您可以将文件名放在日志命名空间中:

logging.test_filename = 'my_log_file.txt'

那么你现有的 loggingpy.conf 文件应该可以工作了

您应该能够在您的模块中使用您喜欢的任何东西(在合理范围内 - 我不会尝试 logging.config = 'something')来污染日志记录命名空间,这应该使它可以被配置文件引用。

【讨论】:

  • 这很简单,效果很好。通过 Sean 在下面的回答,您甚至可以执行 args=(os.path.join('.', test_filename),) 来帮助将文件放在您想要的位置。谢谢!
【解决方案3】:

args 语句在 logging.config.py_install_handlers 使用 eval 解析。所以你可以将代码添加到args

[handler_handRoot]
class=FileHandler
level=INFO
formatter=formRoot
args=(os.getenv("LOG_FILE","default_value"),)

现在您只需要填充环境变量。

【讨论】:

  • 太棒了!如此简单。
  • 当使用 dictConfig 而不是 fileConfig 时,此选项可以工作吗?
【解决方案4】:

这是非常hacky,所以我不会推荐它。但是,如果您出于某种原因不想添加到日志命名空间,您可以通过命令行参数传递日志文件名,然后使用 sys.argv[1] 访问它(sys.argv[0] 是脚本名称)。

[handler_handRoot]
class=FileHandler
level=INFO
formatter=formRoot
args=(sys.argv[1],)

【讨论】:

  • 这很好,因为它指出某些东西在日志命名空间(如 sys.* 和 os.*)中可用,但在您的本地命名空间中不可用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-17
  • 1970-01-01
  • 1970-01-01
  • 2018-10-12
  • 2010-09-30
  • 2020-01-03
  • 1970-01-01
相关资源
最近更新 更多