Ведение журнала Python с параметрами запроса журнала в приложении Fastapi

У меня есть приложение fastapi, и я хочу регистрировать каждый сделанный по нему запрос. Я пытаюсь использовать для этого loguru и uvicorn, но я не знаю, как распечатать заголовки и параметры запроса (если они есть), связанные с каждым запросом.

Я хочу что-то вроде этого:

INFO 2020-08-13 13:36:33.494 uvicorn.protocols.http.h11_impl:send - 127.0.0.1:52660 - "GET 
/url1/url2/ HTTP/1.1" 400 params={"some": value, "some1":value}

Есть способ? Спасибо за вашу помощь.

Вот несколько ссылок:

loguru uvicorn fastapi


person Master Yoda    schedule 13.08.2020    source источник


Ответы (1)


Вы можете использовать промежуточное ПО для регистрации каждого запроса:

import sys

import uvicorn

from fastapi import FastAPI, Request
from loguru import logger
from starlette.routing import Match

logger.remove()
logger.add(sys.stdout, colorize=True, format="<green>{time:HH:mm:ss}</green> | {level} | <level>{message}</level>")
app = FastAPI()


@app.middleware("http")
async def log_middle(request: Request, call_next):
    logger.debug(f"{request.method} {request.url}")
    routes = request.app.router.routes
    logger.debug("Params:")
    for route in routes:
        match, scope = route.matches(request)
        if match == Match.FULL:
            for name, value in scope["path_params"].items():
                logger.debug(f"\t{name}: {value}")
    logger.debug("Headers:")
    for name, value in request.headers.items():
        logger.debug(f"\t{name}: {value}")

    response = await call_next(request)
    return response


@app.get("/{param1}/{param2}")
async def path_operation(param1: str, param2: str):
    return {'param1': param1, 'param2': param2}


if __name__ == "__main__":
    uvicorn.run("app:app", host="localhost", port=8001)

ОБНОВЛЕНИЕ: также может использоваться зависимость от уровня маршрутизатора (спасибо @lsabi в комментариях ниже):

import sys

import uvicorn

from fastapi import FastAPI, Request, APIRouter, Depends
from loguru import logger
from starlette.routing import Match

logger.remove()
logger.add(sys.stdout, colorize=True, format="<green>{time:HH:mm:ss}</green> | {level} | <level>{message}</level>")
app = FastAPI()

router = APIRouter()


async def logging_dependency(request: Request):
    logger.debug(f"{request.method} {request.url}")
    logger.debug("Params:")
    for name, value in request.path_params.items():
        logger.debug(f"\t{name}: {value}")
    logger.debug("Headers:")
    for name, value in request.headers.items():
        logger.debug(f"\t{name}: {value}")


@router.get("/{param1}/{param2}")
async def path_operation(param1: str, param2: str):
    return {'param1': param1, 'param2': param2}

app.include_router(router, dependencies=[Depends(logging_dependency)])

if __name__ == "__main__":
    uvicorn.run("app:app", host="localhost", port=8001)

curl http://localhost:8001/admin/home

Выход:

16:06:43 | DEBUG | GET http://localhost:8001/admin/home
16:06:43 | DEBUG | Params:
16:06:43 | DEBUG |  param1: admin
16:06:43 | DEBUG |  param2: home
16:06:43 | DEBUG | Headers:
16:06:43 | DEBUG |  host: localhost:8001
16:06:43 | DEBUG |  user-agent: curl/7.64.0
16:06:43 | DEBUG |  accept: */*
person alex_noname    schedule 14.08.2020
comment
Также можно использовать зависимость, чтобы пути URL-адресов могли регистрироваться независимо или вместе. - person lsabi; 14.08.2020
comment
Спасибо!! это действительно помогает мне решить проблему !! ... У меня только один вопрос ... Я заменяю sys.stdout на log / access.log для сохранения в файл ... но формат выглядит очень плохо ... любой идея? еще раз спасибо !! - person Master Yoda; 14.08.2020
comment
Вы можете создать свой собственный формат loguru.readthedocs.io/en/stable/api/ logger.html - person alex_noname; 14.08.2020
comment
@AlexNoname Я знаю ... вот что я имею в виду ... ошибка символа prnt.sc/tzqx95 - person Master Yoda; 14.08.2020
comment
Попробуйте отключить colorize = False - person alex_noname; 14.08.2020