I am trying to capture the time taken by api using fastapi in python with below method:
import string, time, random, logging
from starlette.requests import Request
@app.middleware("http")
async def log_requests(request: Request, call_next):
idem = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
logger.info(f"rid={idem} start request path={request.url.path}")
start_time = time.time()
response = await call_next(request)
process_time = (time.time() - start_time) * 1000
formatted_process_time = '{0:.2f}'.format(process_time)
logger.info(f"rid={idem} completed_in={formatted_process_time}ms status_code={response.status_code}")
return response
I want to capture the unique id idem
in @router.post
section written as follows but it is giving error:
import logging as log
@router.post("/infer/", response_description="AD Data Infer")
async def ad_infer_algorithm(ad_infer_config: ADInferConfigSchema = Body(...)):
log.info("Executing AD Train Algorithm with config"+idem)
return "2"
Kindly help
FastAPI has a state
attribute on the request
object. This allows you to attach state to a request from a middleware, and then access that state in your controller (or in another middleware).
Since you already have the request
object available in your middleware, you can just attach idem
to the request state there:
async def log_requests(request: Request, call_next):
idem = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
request.state.idem = idem
(Side note: you can probably replace that random.choices
call with secrets.token_urlsafe
to get a randomly generated identifier (unless you need to control upper vs lower case identifiers - since you didn't include ascii_lowercase).
You can then access that state in your view controller:
@router.post("/infer/", response_description="AD Data Infer")
async def ad_infer_algorithm(request: Request, ad_infer_config: ADInferConfigSchema = Body(...)):
log.info("Executing AD Train Algorithm with config" + request.state.idem)
return "2"
(Another side note: the logging commands should usually use placeholders (%s
) and then the variables as arguments: log.info("Executing AD Train Algorithm with config %s", request.state.idem)