fastapi:第十三章:记录日志时记录下详细的请求信息
一,代码:
1,公用函数
# app/utils/log_util.py
import time
import json
from fastapi import Request, FastAPI
'''
当你把包含中文的 Query 参数放入字典,并使用 json.dumps() 转成字符串写入日志或文件时,默认会进行 Unicode 转义。
解决方法:添加 ensure_ascii=False 参数
'''
# 得到要写日志的内容,没有响应时
async def get_query_param(request: Request):
# 计算响应时间并记录响应体(如果需要)
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
ip = request.client.host
method = request.method
user_agent = str(request.headers.get("user-agent", "Unknown"))
log_content = current_time+" "+ip+" "+method+" "+str(request.url)+" \n"
log_content += user_agent+" \n"
# 得到请求参数
query_params = dict(request.query_params)
if query_params:
log_content += "query:"+json.dumps(query_params,ensure_ascii=False)+"\n"
# 获取 路径参数 (Path Params)
path_params = request.path_params
if path_params:
log_content += "path:"+json.dumps(query_params,ensure_ascii=False)+"\n"
# 得到 form参数
form_params = await get_form_param(request)
print("form:", form_params)
log_content += "form:"+json.dumps(form_params,ensure_ascii=False)+"\n"
return log_content
async def get_form_param(request: Request):
# 检查是否是 POST 请求,且 Content-Type 是表单类型
content_type = request.headers.get("content-type", "")
is_form = "application/x-www-form-urlencoded" in content_type or "multipart/form-data" in content_type
if request.method == "POST" and is_form:
try:
# 转换为标准 Python 字典供日志使用
form_data = await request.form()
form_dict = dict(form_data)
# 打印或写入日志
print(f"[Form 日志] 提交的表单参数为: {form_dict}")
return form_dict
except Exception as e:
print(f"[Form 日志] 解析表单失败: {e}")
return {}
2,异常记录
# 4. 捕获系统未知异常 (如: 代码崩溃、数据库连接断开 500)
@app.exception_handler(Exception)
async def all_exception_handler(request: Request, exc: Exception):
# 注意:生产环境应将 exc 记录到日志系统(如 loguru)
params = await get_query_param(request)
logger.exception(f"服务器内部崩溃 -> {params}")
content = BaseResponse(code=500, msg="服务器内部错误,请稍后再试", data=None).model_dump()
return JSONResponse(status_code=500, content=content)
二,测试效果:
查看日志:
2026-05-24 14:03:29.361 | ERROR | app.core.exceptions:all_exception_handler:41 - 服务器内部崩溃 -> 2026-05-24 14:03:29 127.0.0.1 GET http://127.0.0.1:8000/products/all?name=%E8%B5%B5%E5%9B%9B&age=55
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36
query:{"name": "赵四", "age": "55"}
form:{}
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/local/soft/python3.10.19/lib/python3.10/multiprocessing/spawn.py", line 116, in spawn_main
exitcode = _main(fd, parent_sentinel)
│ │ └ 4
│ └ 7
└ <function _main at 0x7be9d3407b50>
File "/usr/local/soft/python3.10.19/lib/python3.10/multiprocessing/spawn.py", line 129, in _main
return self._bootstrap(parent_sentinel)
│ │ └ 4
│ └ <function BaseProcess._bootstrap at 0x7be9d353a200>
└ <SpawnProcess name='SpawnProcess-25' parent=4179 started>
File "/usr/local/soft/python3.10.19/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
self.run()
│ └ <function BaseProcess.run at 0x7be9d3539870>
└ <SpawnProcess name='SpawnProcess-25' parent=4179 started>
File "/usr/local/soft/python3.10.19/lib/python3.10/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
│ │ │ │ │ └ {'config': <uvicorn.config.Config object at 0x7be9d341b220>, 'target': <bound method Server.run of <uvicorn.server.Server obj...
│ │ │ │ └ <SpawnProcess name='SpawnProcess-25' parent=4179 started>
│ │ │ └ ()
│ │ └ <SpawnProcess name='SpawnProcess-25' parent=4179 started>
│ └ <function subprocess_started at 0x7be9d28c6e60>
└ <SpawnProcess name='SpawnProcess-25' parent=4179 started>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
target(sockets=sockets)
│ └ [<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8000)>]
└ <bound method Server.run of <uvicorn.server.Server object at 0x7be9d341b280>>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/uvicorn/server.py", line 75, in run
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
│ │ │ │ │ │ └ <function Config.get_loop_factory at 0x7be9d2abfa30>
│ │ │ │ │ └ <uvicorn.config.Config object at 0x7be9d341b220>
│ │ │ │ └ <uvicorn.server.Server object at 0x7be9d341b280>
│ │ │ └ [<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8000)>]
│ │ └ <function Server.serve at 0x7be9d28c5ea0>
│ └ <uvicorn.server.Server object at 0x7be9d341b280>
└ <function asyncio_run at 0x7be9d2a72950>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/uvicorn/_compat.py", line 60, in asyncio_run
return loop.run_until_complete(main)
│ │ └ <coroutine object Server.serve at 0x7be9d2889c40>
│ └ <function BaseEventLoop.run_until_complete at 0x7be9d2c6d630>
└ <_UnixSelectorEventLoop running=True closed=False debug=False>
File "/usr/local/soft/python3.10.19/lib/python3.10/asyncio/base_events.py", line 636, in run_until_complete
self.run_forever()
│ └ <function BaseEventLoop.run_forever at 0x7be9d2c6d5a0>
└ <_UnixSelectorEventLoop running=True closed=False debug=False>
File "/usr/local/soft/python3.10.19/lib/python3.10/asyncio/base_events.py", line 603, in run_forever
self._run_once()
│ └ <function BaseEventLoop._run_once at 0x7be9d2c6f0a0>
└ <_UnixSelectorEventLoop running=True closed=False debug=False>
File "/usr/local/soft/python3.10.19/lib/python3.10/asyncio/base_events.py", line 1909, in _run_once
handle._run()
│ └ <function Handle._run at 0x7be9d2dce440>
└ <Handle Task.task_wakeup(<Future finis...ion by zero')>)>
File "/usr/local/soft/python3.10.19/lib/python3.10/asyncio/events.py", line 80, in _run
self._context.run(self._callback, *self._args)
│ │ │ │ │ └ <member '_args' of 'Handle' objects>
│ │ │ │ └ <Handle Task.task_wakeup(<Future finis...ion by zero')>)>
│ │ │ └ <member '_callback' of 'Handle' objects>
│ │ └ <Handle Task.task_wakeup(<Future finis...ion by zero')>)>
│ └ <member '_context' of 'Handle' objects>
└ <Handle Task.task_wakeup(<Future finis...ion by zero')>)>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 415, in run_asgi
result = await app( # type: ignore[func-returns-value]
└ <uvicorn.middleware.proxy_headers.ProxyHeadersMiddleware object at 0x7be9d29099c0>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 56, in __call__
return await self.app(scope, receive, send)
│ │ │ │ └ <bound method RequestResponseCycle.send of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
│ └ <fastapi.applications.FastAPI object at 0x7be9d2909b70>
└ <uvicorn.middleware.proxy_headers.ProxyHeadersMiddleware object at 0x7be9d29099c0>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/fastapi/applications.py", line 1159, in __call__
await super().__call__(scope, receive, send)
│ │ └ <bound method RequestResponseCycle.send of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
└ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/applications.py", line 90, in __call__
await self.middleware_stack(scope, receive, send)
│ │ │ │ └ <bound method RequestResponseCycle.send of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
│ └ <starlette.middleware.errors.ServerErrorMiddleware object at 0x7be9d106c2e0>
└ <fastapi.applications.FastAPI object at 0x7be9d2909b70>
> File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
│ │ │ │ └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7be9d107c700>
│ │ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
│ └ <starlette.middleware.exceptions.ExceptionMiddleware object at 0x7be9d106c310>
└ <starlette.middleware.errors.ServerErrorMiddleware object at 0x7be9d106c2e0>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 63, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
│ │ │ │ │ │ └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7be9d107c700>
│ │ │ │ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ │ │ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
│ │ │ └ <starlette.requests.Request object at 0x7be9d106ec50>
│ │ └ <fastapi.middleware.asyncexitstack.AsyncExitStackMiddleware object at 0x7be9d106c370>
│ └ <starlette.middleware.exceptions.ExceptionMiddleware object at 0x7be9d106c310>
└ <function wrap_app_handling_exceptions at 0x7be9d1b19f30>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
raise exc
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
await app(scope, receive, sender)
│ │ │ └ <function wrap_app_handling_exceptions.<locals>.wrapped_app.<locals>.sender at 0x7be9d107c790>
│ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
└ <fastapi.middleware.asyncexitstack.AsyncExitStackMiddleware object at 0x7be9d106c370>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
await self.app(scope, receive, send)
│ │ │ │ └ <function wrap_app_handling_exceptions.<locals>.wrapped_app.<locals>.sender at 0x7be9d107c790>
│ │ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
│ └ <fastapi.routing.APIRouter object at 0x7be9d1045f30>
└ <fastapi.middleware.asyncexitstack.AsyncExitStackMiddleware object at 0x7be9d106c370>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/routing.py", line 660, in __call__
await self.middleware_stack(scope, receive, send)
│ │ │ │ └ <function wrap_app_handling_exceptions.<locals>.wrapped_app.<locals>.sender at 0x7be9d107c790>
│ │ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
│ └ <bound method Router.app of <fastapi.routing.APIRouter object at 0x7be9d1045f30>>
└ <fastapi.routing.APIRouter object at 0x7be9d1045f30>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/routing.py", line 680, in app
await route.handle(scope, receive, send)
│ │ │ │ └ <function wrap_app_handling_exceptions.<locals>.wrapped_app.<locals>.sender at 0x7be9d107c790>
│ │ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
│ └ <function Route.handle at 0x7be9d1b1b640>
└ APIRoute(path='/products/all', name='get_all_products', methods=['GET'])
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
await self.app(scope, receive, send)
│ │ │ │ └ <function wrap_app_handling_exceptions.<locals>.wrapped_app.<locals>.sender at 0x7be9d107c790>
│ │ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
│ └ <function request_response.<locals>.app at 0x7be9d10435b0>
└ APIRoute(path='/products/all', name='get_all_products', methods=['GET'])
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/fastapi/routing.py", line 134, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
│ │ │ │ │ └ <function wrap_app_handling_exceptions.<locals>.wrapped_app.<locals>.sender at 0x7be9d107c790>
│ │ │ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ │ │ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
│ │ └ <starlette.requests.Request object at 0x7be9d106ee30>
│ └ <function request_response.<locals>.app.<locals>.app at 0x7be9d107c820>
└ <function wrap_app_handling_exceptions at 0x7be9d1b19f30>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
raise exc
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
await app(scope, receive, sender)
│ │ │ └ <function wrap_app_handling_exceptions.<locals>.wrapped_app.<locals>.sender at 0x7be9d107c8b0>
│ │ └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.h11_impl.RequestResponseCycle object at 0x7be9d106f640>>
│ └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.3'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8000), 'cl...
└ <function request_response.<locals>.app.<locals>.app at 0x7be9d107c820>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/fastapi/routing.py", line 120, in app
response = await f(request)
│ └ <starlette.requests.Request object at 0x7be9d106ee30>
└ <function get_request_handler.<locals>.app at 0x7be9d1043640>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/fastapi/routing.py", line 674, in app
raw_response = await run_endpoint_function(
└ <function run_endpoint_function at 0x7be9d1b3d480>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/fastapi/routing.py", line 330, in run_endpoint_function
return await run_in_threadpool(dependant.call, **values)
│ │ │ └ {}
│ │ └ <function get_all_products at 0x7be9d1a70ca0>
│ └ Dependant(path_params=[], query_params=[], header_params=[], cookie_params=[], body_params=[], dependencies=[], name=None, ca...
└ <function run_in_threadpool at 0x7be9d1d081f0>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/starlette/concurrency.py", line 32, in run_in_threadpool
return await anyio.to_thread.run_sync(func)
│ │ │ └ functools.partial(<function get_all_products at 0x7be9d1a70ca0>)
│ │ └ <function run_sync at 0x7be9d2816560>
│ └ <module 'anyio.to_thread' from '/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/anyio/to_thread.py'>
└ <module 'anyio' from '/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/anyio/__init__.py'>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/anyio/to_thread.py", line 63, in run_sync
return await get_async_backend().run_sync_in_worker_thread(
└ <function get_async_backend at 0x7be9d2815ea0>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 2518, in run_sync_in_worker_thread
return await future
└ <Future finished exception=ZeroDivisionError('division by zero')>
File "/data/python/fastapi/demo1/venv/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 1002, in run
result = context.run(func, *args)
File "/data/python/fastapi/demo1/app/api/products.py", line 12, in get_all_products
b = 100 / a
└ 0
ZeroDivisionError: division by zero
浙公网安备 33010602011771号