使用Gunicorn搭配Uvicorn时,为何要将日志关联到错误日志记录器?
Gunicorn搭配Uvicorn时的日志统一处理优化方案
当使用Gunicorn作为Uvicorn的进程管理器时,默认情况下Uvicorn的访问日志、异常信息不会输出到Gunicorn的日志体系中。
常见的解决方案是通过代码复用Gunicorn错误日志处理器:
gunicorn_error_logger = logging.getLogger("gunicorn.error") uvicorn_access_logger = logging.getLogger("uvicorn.access") uvicorn_access_logger.handlers = gunicorn_error_logger.handlers
但这个方案存在明显缺陷:
- 违背了Gunicorn与Uvicorn各自区分访问日志、错误日志的设计初衷
- Uvicorn作为Worker运行时,已原生将日志记录器关联到Gunicorn提供的记录器,无需额外手动绑定
- 会导致Uvicorn访问日志默认输出到STDERR而非STDOUT,不符合日志分流的常规规范
更优方案1:利用Uvicorn Worker原生日志关联(推荐)
Uvicorn的UvicornWorker已内置日志关联逻辑,只需在启动Gunicorn时指定正确的日志输出配置即可:
gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --access-logfile - --error-logfile -
其中:
--access-logfile -表示将Gunicorn(及关联的Uvicorn)访问日志输出到STDOUT--error-logfile -表示将错误日志输出到STDERR
Uvicorn的日志会自动继承Gunicorn的处理器,实现访问日志、错误日志的正确分流,无需额外代码配置。
更优方案2:自定义日志配置文件
若需要更精细的日志格式或分流规则,可创建Gunicorn日志配置文件(如logging.conf):
[loggers] keys=root,gunicorn.error,gunicorn.access,uvicorn.access,uvicorn.error [handlers] keys=console_access,console_error [formatters] keys=generic [logger_root] level=INFO handlers= [logger_gunicorn.error] level=INFO handlers=console_error propagate=0 qualname=gunicorn.error [logger_gunicorn.access] level=INFO handlers=console_access propagate=0 qualname=gunicorn.access [logger_uvicorn.access] level=INFO handlers=console_access propagate=0 qualname=uvicorn.access [logger_uvicorn.error] level=INFO handlers=console_error propagate=0 qualname=uvicorn.error [handler_console_access] class=StreamHandler formatter=generic args=(sys.stdout,) [handler_console_error] class=StreamHandler formatter=generic args=(sys.stderr,) [formatter_generic] format=%(asctime)s [%(process)d] [%(levelname)s] %(message)s datefmt=%Y-%m-%d %H:%M:%S
启动时指定该配置文件:
gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --log-config logging.conf
该方案可完全统一Gunicorn与Uvicorn的日志格式与输出目标,严格遵循访问日志、错误日志的分流设计。
内容的提问来源于stack exchange,提问作者Matt Sanders
相关产品推荐
相关产品推荐

