我希望gunicorn.error使用以下基于键值的日志格式,而不是gunicorn/glogging.py中定义的默认格式
'format': 'timestamp=%(asctime)s pid=%(process)d loglevel=%(levelname)s msg=%(message)s'`
在我的gunicorn配置文件中:
import logging.config
workers = 2
bind = "127.0.0.1:8000"
loglevel = 'INFO'
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'key_value': {
'format': 'timestamp=%(asctime)s pid=%(process)d loglevel=%(levelname)s msg=%(message)s'
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'key_value',
'stream': 'ext://sys.stdout'
}
},
'loggers': {
'gunicorn.error': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False,
},
'flask.app': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False,
}
},
}
logging.config.dictConfig(LOGGING)
Gunicorn以我的自定义格式和默认格式记录了两次:
timestamp=2016-12-11 15:20:49,559 pid=22110 loglevel=INFO msg=Starting gunicorn 19.6.0
[2016-12-11 15:20:49 +0000] [22110] [INFO] Starting gunicorn 19.6.0
timestamp=2016-12-11 15:20:49,559 pid=22110 loglevel=INFO msg=Listening at: http://127.0.0.1:8000 (22110)
[2016-12-11 15:20:49 +0000] [22110] [INFO] Listening at: http://127.0.0.1:8000 (22110)
timestamp=2016-12-11 15:20:49,559 pid=22110 loglevel=INFO msg=Using worker: sync
[2016-12-11 15:20:49 +0000] [22110] [INFO] Using worker: sync
timestamp=2016-12-11 15:20:49,560 pid=22115 loglevel=INFO msg=Booting worker with pid: 22115
[2016-12-11 15:20:49 +0000] [22115] [INFO] Booting worker with pid: 22115
timestamp=2016-12-11 15:20:49,595 pid=22115 loglevel=INFO msg=Starting Flask application
timestamp=2016-12-11 15:20:49,659 pid=22120 loglevel=INFO msg=Booting worker with pid: 22120
[2016-12-11 15:20:49 +0000] [22120] [INFO] Booting worker with pid: 22120
timestamp=2016-12-11 15:20:49,693 pid=22120 loglevel=INFO msg=Starting Flask application
我使用logging_tree库查看了已配置的记录器,我看到两个黑角记录器向控制台发出:
<--""
Level WARNING
|
o<--"flask"
| Level NOTSET so inherits level WARNING
| |
| o "flask.app"
| Level INFO
| Propagate OFF
| Handler Stream <open file '<stdout>', mode 'w' at 0x7f86676b1150>
| Level INFO
| Formatter fmt='timestamp=%(asctime)s pid=%(process)d loglevel=%(levelname)s msg=%(message)s' datefmt=None
|
o<--"gunicorn"
Level NOTSET so inherits level WARNING
|
o "gunicorn.access"
| Level INFO
| Propagate OFF
|
o "gunicorn.error"
| Level INFO
| Propagate OFF
| Handler Stream <open file '<stdout>', mode 'w' at 0x7f86676b1150>
| Level INFO
| Formatter fmt='timestamp=%(asctime)s pid=%(process)d loglevel=%(levelname)s msg=%(message)s' datefmt=None
| Handler Stream <open file '<stderr>', mode 'w' at 0x7f86676b11e0>
| Formatter fmt='%(asctime)s [%(process)d] [%(levelname)s] %(message)s' datefmt='[%Y-%m-%d %H:%M:%S %z]'
|
o<--"gunicorn.http"
Level NOTSET so inherits level WARNING
|
o<--"gunicorn.http.wsgi"
Level NOTSET so inherits level WARNING
Gunicorn的docs说可以指定要使用的记录器类,但我不知道如何做到这一点。
发布于 2021-07-25 18:20:16
gunicorn
的日志记录的问题是,它通常在你的代码之前运行在相同的Python进程中,configures logging在你的任何与WSGI相关的代码运行之前记录一些消息,你有机会按照自己的方式配置日志记录。
$ gunicorn --help | grep logger
--logger-class STRING
The logger you want to use to log events in Gunicorn.
请注意,不推荐使用incremental configuration (即gunicorn
调用dictConfig
一次,然后由您调用),这可能也不是您想要的:
...一旦设置了配置,就不存在在运行时任意更改记录器、处理程序、过滤器、格式化程序的对象图的令人信服的情况;记录器和处理程序的冗长可以仅通过设置级别(对于记录器,传播标志)来控制。在多线程环境中,以安全的方式任意更改对象图是有问题的;虽然并非不可能,但其带来的好处并不值得为实现增加复杂性。
因此,我建议将gunicorn
视为regular library with regards to logging,并完全禁用其日志记录配置(有利于您的应用程序)。
这是一个简单的应用程序,它具有HTTP和控制台入口点,这两个入口点应该具有相同的日志配置:
logging_cfg = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'KeyValueFormatter': {
'format': (
'timestamp=%(asctime)s pid=%(process)d '
'loglevel=%(levelname)s msg=%(message)s'
)
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'KeyValueFormatter',
}
},
'loggers': {
'gunicorn.access': {
'propagate': True,
},
'gunicorn.error': {
'propagate': True,
},
},
'root': {
'level': 'INFO',
'handlers': ['console'],
}
}
这里是它的实现,app.py
。
import logging.config
from gunicorn import glogging
logger = logging.getLogger(__name__)
def get_result():
logger.info('Calculating result')
return b'Hello world!'
def wsgi_app(environ, start_response):
result = get_result()
start_response('200 OK', [('Content-Type', 'text/html')])
return [result]
def configure_logging():
logging.config.dictConfig(logging_cfg)
class UniformLogger(glogging.Logger):
def setup(self, cfg):
configure_logging()
if __name__ == '__main__':
configure_logging()
print(get_result())
如果你运行python app.py
,你应该会得到:
timestamp=2021-07-25 12:09:04,488 pid=4599 loglevel=INFO msg=Calculating result
b'Hello world!'
如果先运行gunicorn --logger-class=app.UniformLogger app:wsgi_app
,然后运行curl localhost:8000
timestamp=2021-07-25 12:16:56,892 pid=4874 loglevel=INFO msg=Starting gunicorn 20.1.0
timestamp=2021-07-25 12:16:56,892 pid=4874 loglevel=INFO msg=Listening at: http://127.0.0.1:8000 (4874)
timestamp=2021-07-25 12:16:56,893 pid=4874 loglevel=INFO msg=Using worker: sync
timestamp=2021-07-25 12:16:56,894 pid=4876 loglevel=INFO msg=Booting worker with pid: 4876
timestamp=2021-07-25 12:17:06,926 pid=4876 loglevel=INFO msg=Calculating result
https://stackoverflow.com/questions/41087790
复制相似问题