【问题标题】:Evaluate statements from within Python logging YAML config file从 Python 日志记录 YAML 配置文件中评估语句
【发布时间】:2016-07-25 15:23:33
【问题描述】:

考虑 Python logging YAML 配置文件的以下 sn-p:

version: 1
formatters:
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
  logfile:
    class: logging.handlers.TimedRotatingFileHandler
    level: DEBUG
    filename: some_fancy_import_name.generate_filename_called_error
    backupCount: 5
    formatter: simple

我想以这种方式加载这个 YAML 配置文件:

with open('logging.yaml', 'r') as fd:
    config = yaml.safe_load(fd.read())
logging.config.dictConfig(config)

特别注意handler 应写入日志的filename。在普通的 Python 代码中,我希望 some_fancy_import_name.generate_filename_called_errorlog 生成字符串 'error.log'。总而言之,我想说这个日志处理程序应该写入当前目录下的文件'error.log'

但是,事实证明,情况并非如此。当我查看当前目录时,我看到了一个名为 'some_fancy_import_name.generate_filename_called_errorlog' 的文件。

为什么要经历这些麻烦?

我希望以编程方式确定filename。我已经成功尝试通过这种方式使用普通 Python 脚本配置日志记录:

# fancy import name
from os import environ as env

# Programmatically determine filename path
log_location = env.get('OPENSHIFT_LOG_DIR', '.')
log_filename = os.path.join(log_location, 'error')
handler = logging.handlers.TimedRotatingFileHandler(log_filename)

查看log_filename 路径是如何从环境变量中推断出来的。

我想将其转换为 YAML 配置文件。有可能吗?

也许我可能需要挖掘由yaml.safe_load(fd.read()) 生成的dict 并做一些eval() 的东西?

【问题讨论】:

  • 不要在问题本身中回答问题。要么接受 flyx 的答案,要么将您的解决方案作为答案发布。

标签: python logging yaml


【解决方案1】:

您可以添加自定义构造函数并使用特殊标记标记值,以便在加载时执行构造函数:

import yaml

def eval_constructor(loader, node):
  return eval(loader.construct_scalar(node))

yaml.add_constructor(u'!eval', eval_constructor)

some_value = '123'

config = yaml.load("""
version: 1
formatters:
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
  logfile:
    class: logging.handlers.TimedRotatingFileHandler
    level: DEBUG
    filename: !eval some_value
    backupCount: 5
    formatter: simple
""")

print config['handlers']['logfile']['filename']

这将打印123,因为值some_value 具有标签!eval,因此加载了eval_constructor

注意evaling 配置数据的安全隐患。任意Python代码写入YAML文件即可执行!

【讨论】:

    【解决方案2】:

    解决方案

    感谢flyx's answer,我就是这样做的:

    import logging
    import yaml
    from os import environ as env
    
    def constructor_logfilename(loader, node):
        value = loader.construct_scalar(node)
        return os.path.join(env.get('OPENSHIFT_LOG_DIR', '.'), value)
    
    yaml.add_constructor(u'!logfilename', constructor_logfilename)
    with open('logging.yaml', 'r') as fd:
        config = yaml.load(fd.read())
    logging.config.dictConfig(config)
    

    logging.yaml 文件中,这里是重要的sn-p:

    ...
    filename: !logfilename error.log
    ...
    

    【讨论】:

      【解决方案3】:

      我刚刚自己提出了这个问题,我以一种更无聊的方式解决了这个问题。我从 yaml 文件中省略了日志文件处理程序的文件名属性,并将其添加到 yaml.load 创建的配置字典中,如下所示:

      with open('logging.yaml', 'r') as fd:
          config = yaml.load(fd.read())
      config['handlers']['logfile']['filename'] = generate_logfile_name(...)
      logging.config.dictConfig(config)
      

      【讨论】:

        猜你喜欢
        • 2018-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-12
        • 1970-01-01
        • 2018-09-20
        • 2020-01-03
        • 1970-01-01
        相关资源
        最近更新 更多