fastapi项目使用loguru,如何在uvicorn代码式启动时,也能正常打印出请求日志?

新手上路,请多包涵

问题描述

最近在开发一个fastapi项目中使用到loguru进行日志打印,但是uvicorn两种启动方式下,效果不太一样。通过uvicorn main:app的方式可以将HTTP请求("GET /debug/ HTTP/1.1")打印出来:

2022-37-33 14:37:25.277 | MainThread | INFO | server:serve:84 - Started server process [13240]
2022-37-33 14:37:25.279 | MainThread | INFO | server:serve:84 - Started server process [13240]
2022-37-33 14:37:25.280 | MainThread | INFO | on:startup:45 - Waiting for application startup.
2022-37-33 14:37:25.281 | MainThread | INFO | on:startup:45 - Waiting for application startup.
2022-37-33 14:37:25.282 | MainThread | INFO | on:startup:59 - Application startup complete.
2022-37-33 14:37:25.283 | MainThread | INFO | on:startup:59 - Application startup complete.
2022-37-33 14:37:25.284 | MainThread | INFO | server:_log_started_message:222 - Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
2022-37-33 14:37:25.285 | MainThread | INFO | server:_log_started_message:222 - Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
2022-37-33 14:37:50.021 | AnyIO worker thread | INFO | main:debug_item:82 - 测试主流程
2022-37-33 14:37:50.026 | MainThread | INFO | httptools_impl:send:447 - 127.0.0.1:51119 - "GET /debug/ HTTP/1.1" 200

使用代码式启动时,却没能将HTTP请求打印

2022-38-33 14:38:53.886 | MainThread | INFO | server : serve:84 -  Started server process [1828]
2022-38-33 14:38:53.889 | MainThread | INFO | on : startup:45 -  Waiting for application startup.
2022-38-33 14:38:53.890 | MainThread | INFO | on : startup:59 -  Application startup complete.
2022-38-33 14:38:53.892 | MainThread | INFO | server : _log_started_message:222 -  Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
2022-38-33 14:38:58.930 | AnyIO worker thread | INFO | main : debug_item:82 -  测试主流程

main.py中的启动代码

if __name__ == "__main__":
    config = uvicorn.Config("main:app", host=SERVEICE_HOST_IP, port=int(SERVICE_HOST_PORT), workers=1)
    server = uvicorn.Server(config)
    server.run()

尝试解决

一开始以为代码启动中access_log参数影响,将其置为True,没有效果。

if __name__ == "__main__":
    config = uvicorn.Config("main:app", host=SERVEICE_HOST_IP, port=int(SERVICE_HOST_PORT), access_log=True, workers=1)
    server = uvicorn.Server(config)
    server.run()

相关代码

logger.py

import logging
from types import FrameType
from typing import cast
from loguru import logger
from .setting import  loguru_config


class InterceptHandler(logging.Handler):
    def emit(self, record: logging.LogRecord) -> None:  # pragma: no cover
        # Get corresponding Loguru level if it exists
        try:
            level = logger.level(record.levelname).name
        except ValueError:
            level = str(record.levelno)

        # Find caller from where originated the logged message
        frame, depth = logging.currentframe(), 2
        while frame.f_code.co_filename == logging.__file__:  # noqa: WPS609
            frame = cast(FrameType, frame.f_back)
            depth += 1

        logger.opt(depth=depth, exception=record.exc_info).log(
            level, record.getMessage(),
        )
        
LOGGER_NAMES = ("uvicorn.asgi", "uvicorn.access", "uvicorn")

# change handler for default uvicorn logger
logging.getLogger().handlers = [InterceptHandler()]
for logger_name in LOGGER_NAMES:
    logging_logger = logging.getLogger(logger_name)
    logging_logger.handlers = [InterceptHandler()]

logger.configure(**loguru_config)

setting.py

loguru_config = {
    "handlers": [
        {
            "sink": sys.stdout, 
            "level": LOGGING_LEVEL,
            "format": "<green>{time:YYYY-mm-dd HH:mm:ss.SSS}</green> | {thread.name} | <level>{level}</level> | "
                   "<cyan>{module}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"
        },
        {
            "sink": log_file_path, 
            "level": LOGGING_LEVEL,
            "rotation": "10 MB", 
            "retention": "1 week",
            "encoding": 'utf-8',
            "format":"{time:YYYY-mm-dd HH:mm:ss.SSS} | {thread.name} | {level} | {module} : {function}:{line} -  {message}" 
        },
        {
            "sink": err_log_file_path, 
            "serialize": True, 
            "level": 'ERROR', 
            "retention": "1 week",
            "rotation": "10 MB",
            "encoding": 'utf-8',
            "format":"{time:YYYY-mm-dd HH:mm:ss.SSS} | {thread.name} | {level} | {module} : {function}:{line} -  {message}" 
        },
    ],
}
阅读 5.5k
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏