[英]Custom Python logging formatter works with fileConfig but not with dictConfig?
I've been pulling my hair out for hours trying to figure out why these two logging configs, which as far as I can tell should be 100% identical, are not resulting in the same behavior:我已经花了几个小时试图弄清楚为什么这两个日志配置,据我所知应该是 100% 相同的,不会导致相同的行为:
LOGGING_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'root': {
'handlers': ['console'],
'level': 'INFO',
},
'gunicorn.access': {
'level': 'INFO',
'handlers': ['access_console'],
'propagate': False,
'qualname': 'gunicorn.access',
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stderr',
'formatter': 'syslog',
},
'access_console': {
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout',
'formatter': 'docker_access',
},
},
'formatters': {
'syslog': {
'()': 'citi.logging.DockerFormatter',
'fmt': 'SYSLOG %(asctime)s [%(levelname)s] %(name)s: %(message)s',
},
'docker_access': {
'()': 'citi.logging.DockerFormatter',
'fmt': 'GUNICORN_ACCESS %(asctime)s %(message)s',
},
},
}
[loggers]
keys=root,gunicorn.access
[handlers]
keys=console,access_console
[formatters]
keys=syslog,docker_access
[logger_root]
level=INFO
handlers=console
[logger_gunicorn.access]
level=INFO
handlers=access_console
propagate=0
qualname=gunicorn.access
[handler_console]
class=StreamHandler
formatter=syslog
args=(sys.stderr, )
[handler_access_console]
class=StreamHandler
formatter=docker_access
args=(sys.stdout, )
[formatter_syslog]
class=citi.logging.DockerFormatter
format=SYSLOG %(asctime)s [%(levelname)s] %(name)s: %(message)s
[formatter_docker_access]
class=citi.logging.DockerFormatter
format=GUNICORN_ACCESS %(asctime)s %(message)s
When I use logging.config.fileConfig
and pass it the file that contains the second code block, it works fine.当我使用logging.config.fileConfig
并将包含第二个代码块的文件传递给它时,它工作正常。 The gunicorn.access
logger changes its formatter to the custom DockerFormatter
class (which is a simple subclass of logging.Formatter
) with the specified format
string. gunicorn.access
记录器将其格式化程序更改为具有指定format
字符串的自定义DockerFormatter
类(它是logging.Formatter
的简单子类)。 The access logs look like this:访问日志如下所示:
GUNICORN_ACCESS 2021-07-16 18:59:56,454 172.18.0.1 - - "GET /citi/server-status HTTP/1.0" 200 11 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" 11766
But when I use logging.config.dictConfig
and pass it the dict at the top, everything except the custom formatter works.但是当我使用logging.config.dictConfig
并将它传递给顶部的 dict 时,除了自定义格式化程序之外的所有内容都可以工作。 The formatter appears to remain set to the original defaults provided by Gunicorn (maybe??).格式化程序似乎仍然设置为 Gunicorn 提供的原始默认值(也许??)。 The output is:输出是:
172.18.0.1 - - "GET /citi/server-status HTTP/1.0" 200 11 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" 7549
By using the logging_tree
package, I can tell that gunicorn.access
's formatter is some sort of default when using dictConfig
.通过使用logging_tree
包,我可以知道gunicorn.access
的格式化程序在使用dictConfig
时是某种默认dictConfig
。 It should look like this:它应该是这样的:
o<--"gunicorn"
| Level NOTSET so inherits level INFO
| |
| o "gunicorn.access"
| | Level INFO
| | Propagate OFF
| | Handler Stream <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
| | Formatter <citi.logging.DockerFormatter object at 0x7f68240e7d90>
But instead it looks like this:但它看起来像这样:
o<--"gunicorn"
| Level NOTSET so inherits level INFO
| |
| o "gunicorn.access"
| | Level INFO
| | Propagate OFF
| | Handler Stream <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
| | Formatter fmt='%(message)s' datefmt=None
The only difference I can detect in terms of how the DockerFormatter
class is called is that the fileConfig
form calls it with positional arguments, while dictConfig
calls it with (correct) keyword arguments.在DockerFormatter
类的调用方式方面,我可以检测到的唯一区别是fileConfig
表单使用位置参数调用它,而dictConfig
使用(正确的)关键字参数调用它。
What appears to be happening is that the formatter is being constructed correctly, but not assigned correctly.似乎正在发生的是格式化程序正在正确构造,但没有正确分配。 And I can't figure out WHY.我不知道为什么。
The most infuriating thing is that I've actually simplified my logging config quite a bit.最令人气愤的是,我实际上已经大大简化了我的日志配置。 In my full config, I set up a custom structlog
-based formatter, configured in exactly the same manner as syslog
and docker_access
are with DockerFormatter
, but it DOES work.在我的完整配置中,我设置了一个基于structlog
的自定义格式化程序,其配置方式与syslog
和docker_access
与DockerFormatter
配置方式DockerFormatter
,但它确实有效。 I am very frustrated.我很沮丧。 >_< >_<
And of course, my final, last ditch effort before leaving the office for the day (several hours late...) actually works.当然,我在离开办公室前的最后一次努力(迟到了几个小时......)确实有效。 Turns out I was right about Gunicorn's default settings staying in place, because I had completely missed the absolutely essential 'loggers'
subdict in my dictConfig dictionary.事实证明,我对 Gunicorn 的默认设置保持原样是正确的,因为我完全错过了 dictConfig 字典中绝对必要的'loggers'
子词。
It's supposed to look this THIS:它应该是这样的:
LOGGING_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'root': {
'handlers': ['console'],
'level': 'INFO',
},
'loggers' {
'gunicorn.access': {
'level': 'INFO',
'handlers': ['access_console'],
'propagate': False,
'qualname': 'gunicorn.access',
},
}
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.