考虑以下Python logging
YAML配置文件的片段:
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)
特别注意filename
应写入日志的handler
。在普通的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配置文件。有可能吗?
也许我可能需要挖掘dict
生成的yaml.safe_load(fd.read())
并做一些eval()
的事情?
答案 0 :(得分:4)
您可以添加自定义构造函数并使用特殊标记标记该值,以便在加载构造函数时执行它:
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
。
请注意eval
配置数据的安全隐患。任意Python代码都可以通过将其写入YAML文件来执行!
答案 1 :(得分:0)
感谢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
文件中,这是重要的代码段:
...
filename: !logfilename error.log
...
答案 2 :(得分:0)
我刚才遇到了这个问题,然后以一种更无聊的方式进行了处理。我从yaml文件中删除了日志文件处理程序的filename属性,将其添加到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)