FastAPI gunicorn添加日志记录时间戳

时间:2020-05-03 22:38:45

标签: docker logging gunicorn fastapi

我正在使用docker运行FastAPI https://fastapi.tiangolo.com/deployment/

tiangolo/uvicorn-gunicorn-fastapi:python3.7

start.sh看起来像:

exec gunicorn -k uvicorn.workers.UvicornWorker -c "$GUNICORN_CONF" "$APP_MODULE"

我的docker日志看起来没有时间戳:

INFO:     123.123.123.123:48736 - "GET /wp-login.php HTTP/1.0" 404 Not Found
INFO:     123.123.123.123:48808 - "GET /robots.txt HTTP/1.0" 404 Not Found
INFO:     123.123.123.123:48810 - "GET / HTTP/1.0" 200 OK

似乎在使用的gunicorn_conf.py

use_loglevel = os.getenv("LOG_LEVEL", "info")

如何轻松,优雅地用时间戳修改INFO和ERROR的记录器格式?

2 个答案:

答案 0 :(得分:2)

您应该能够使用gunicorn_conf.py文件中的access_log_format变量来修改访问日志的格式。您可以将uvicorn-gunicorn docker映像中使用的gunicorn_conf.py文件this one建立为基础。

答案 1 :(得分:1)

我相信在使用uvicorn / gunicorn / fastapi组合时,access_log_format选项是currently ignored。但这主要是为了编辑日志的%(message)s部分。如果您只想添加时间戳,则应该可以覆盖记录器的行为(尽管默认值对我来说是时间戳)。

我在定义fastapi __init__.py之前,将下面的示例放在app中。

import logging, logging.config

LOG_CONFIG = {
    "version": 1,
    "disable_existing_loggers": True,
    "formatters": {"default": {"format": "%(asctime)s [%(process)s] %(levelname)s: %(message)s"}},
    "handlers": {
        "console": {
            "formatter": "default",
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout",
            "level": "INFO",
        }
    },
    "root": {"handlers": ["console"], "level": "INFO"},
    "loggers": {
        "gunicorn": {"propagate": True},
        "gunicorn.access": {"propagate": True},
        "gunicorn.error": {"propagate": True},
        "uvicorn": {"propagate": True},
        "uvicorn.access": {"propagate": True},
        "uvicorn.error": {"propagate": True},
    },
}

logging.config.dictConfig(LOG_CONFIG)
logger = logging.getLogger(__name__)

请查看this答案,以获取有关记录dict配置的一些好示例。

如果您实际上要编辑uvicorn的访问日志格式,则不确定是否有“官方”方法。在撰写本文时,它们似乎采用their code的硬编码格式:

            if self.access_log:
                self.access_logger.info(
                    '%s - "%s %s HTTP/%s" %d',
                    get_client_addr(self.scope),
                    self.scope["method"],
                    get_path_with_query_string(self.scope),
                    self.scope["http_version"],
                    status_code,
                    extra={"status_code": status_code, "scope": self.scope},
                )

例如,我对打印x-forwarded-for标头值感兴趣。解决该问题的一种丑陋方法是猴子修补uvicorn.protocols.utils.get_client_addr并从传递给它的scope字典中提取所需内容。它恰好具有请求标头。注意:这可能会产生意想不到的后果,特别是如果uvicorn员工将其代码更改为使用get_client_addr来完成除打印值之外的其他操作。

也许有一种方法可以通过使用自定义记录器的自定义工作程序类来实现,但是我也没有看到这样做。

相关问题