Skip to content

Commit a3edaa8

Browse files
committed
feat(server): 添加访问日志中间件并优化日志配置
1. 实现自定义访问日志中间件以记录请求处理时间 2. 禁用uvicorn默认访问日志处理器 优化日志格式化配置
1 parent 80d0355 commit a3edaa8

File tree

7 files changed

+81
-15
lines changed

7 files changed

+81
-15
lines changed

server/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from server.utils.lifespan import lifespan
1313
from server.utils.auth_middleware import is_public_path
1414
from server.utils.common_utils import setup_logging
15+
from server.utils.access_log_middleware import AccessLogMiddleware
1516

1617
# 设置日志配置
1718
setup_logging()
@@ -115,6 +116,9 @@ async def dispatch(self, request: Request, call_next):
115116
return await call_next(request)
116117

117118

119+
# 添加访问日志中间件(记录请求处理时间)
120+
app.add_middleware(AccessLogMiddleware)
121+
118122
# 添加鉴权中间件
119123
app.add_middleware(LoginRateLimitMiddleware)
120124
app.add_middleware(AuthMiddleware)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""访问日志中间件 - 记录请求处理时间"""
2+
3+
import time
4+
import logging
5+
from collections.abc import Callable
6+
7+
from fastapi import Request, Response
8+
from starlette.middleware.base import BaseHTTPMiddleware
9+
10+
# 创建专用的访问日志记录器
11+
access_logger = logging.getLogger("access_logger")
12+
13+
# 设置访问日志记录器
14+
if not access_logger.handlers:
15+
handler = logging.StreamHandler()
16+
formatter = logging.Formatter(fmt="%(asctime)s %(levelname)s: %(message)s", datefmt="%m-%d %H:%M:%S")
17+
handler.setFormatter(formatter)
18+
access_logger.addHandler(handler)
19+
access_logger.setLevel(logging.INFO)
20+
# 避免传播到根日志记录器,防止重复日志
21+
access_logger.propagate = False
22+
23+
24+
def _extract_client_ip(request: Request) -> str:
25+
"""提取客户端IP地址"""
26+
forwarded_for = request.headers.get("x-forwarded-for")
27+
if forwarded_for:
28+
return forwarded_for.split(",")[0].strip()
29+
if request.client:
30+
return request.client.host
31+
return "unknown"
32+
33+
34+
class AccessLogMiddleware(BaseHTTPMiddleware):
35+
"""访问日志中间件 - 记录请求处理时间"""
36+
37+
def __init__(self, app, logger: logging.Logger = None):
38+
super().__init__(app)
39+
self.logger = logger or access_logger
40+
41+
async def dispatch(self, request: Request, call_next: Callable) -> Response:
42+
"""处理请求并记录访问日志"""
43+
# 记录请求开始时间
44+
start_time = time.perf_counter()
45+
46+
# 获取客户端IP
47+
client_ip = _extract_client_ip(request)
48+
49+
# 处理请求
50+
response = await call_next(request)
51+
52+
# 计算处理时间
53+
process_time = time.perf_counter() - start_time
54+
process_time_ms = int(process_time * 1000) # 转换为毫秒
55+
56+
# 格式化日志消息,添加处理时间
57+
log_message = (
58+
f"{client_ip}:{request.client.port if request.client else 'unknown'} - "
59+
f'"{request.method} {request.url.path}{"?" + request.url.query if request.url.query else ""} '
60+
f'HTTP/{request.scope["http_version"]}" '
61+
f"{response.status_code} - {process_time_ms}ms"
62+
)
63+
64+
# 记录日志
65+
self.logger.info(log_message)
66+
67+
return response

server/utils/common_utils.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ def setup_logging():
1919
uvicorn_logger = logging.getLogger("uvicorn")
2020
uvicorn_access_logger = logging.getLogger("uvicorn.access")
2121

22+
# 禁用默认的uvicorn访问日志(因为我们使用自定义中间件)
23+
uvicorn_access_logger.handlers.clear()
24+
2225
# 创建格式化器
2326
formatter = logging.Formatter(fmt="%(asctime)s %(levelname)s: %(message)s", datefmt="%m-%d %H:%M:%S")
2427

25-
# 为所有处理器设置格式化器
28+
# 为uvicorn主日志设置格式化器
2629
for handler in uvicorn_logger.handlers:
2730
handler.setFormatter(formatter)
28-
for handler in uvicorn_access_logger.handlers:
29-
handler.setFormatter(formatter)
3031

3132

3233
async def log_operation(db: Session, user_id: int, operation: str, details: str = None, request: Request = None):

src/agents/common/models.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ def load_chat_model(fully_specified_name: str, **kwargs) -> BaseChatModel:
3232
logger.debug(f"[offical] Loading model {model_spec} with kwargs {kwargs}")
3333
return init_chat_model(model_spec, **kwargs)
3434

35-
3635
elif provider in ["dashscope"]:
3736
from langchain_deepseek import ChatDeepSeek
3837

src/agents/deep_agent/graph.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
"""Deep Agent - 基于create_deep_agent的深度分析智能体"""
22

3-
from langchain.agents.middleware import ModelRequest, dynamic_prompt, SummarizationMiddleware
4-
5-
from langchain.agents import create_agent
6-
from langchain.agents.middleware import TodoListMiddleware
7-
from langchain_anthropic.middleware import AnthropicPromptCachingMiddleware
8-
93
from deepagents.middleware.filesystem import FilesystemMiddleware
104
from deepagents.middleware.patch_tool_calls import PatchToolCallsMiddleware
115
from deepagents.middleware.subagents import SubAgentMiddleware
6+
from langchain.agents import create_agent
7+
from langchain.agents.middleware import ModelRequest, SummarizationMiddleware, TodoListMiddleware, dynamic_prompt
8+
from langchain_anthropic.middleware import AnthropicPromptCachingMiddleware
129

1310
from src.agents.common import BaseAgent, load_chat_model
1411
from src.agents.common.middlewares import context_based_model, inject_attachment_context
@@ -21,9 +18,7 @@
2118

2219
research_sub_agent = {
2320
"name": "research-agent",
24-
"description": (
25-
"利用搜索工具,用于研究更深入的问题。"
26-
),
21+
"description": ("利用搜索工具,用于研究更深入的问题。"),
2722
"system_prompt": (
2823
"你是一位专注的研究员。你的工作是根据用户的问题进行研究。"
2924
"进行彻底的研究,然后用详细的答案回复用户的问题,只有你的最终答案会被传递给用户。"

src/knowledge/implementations/lightrag.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ def _get_embedding_func(self, embed_info: dict):
235235
model=model_name,
236236
api_key=config_dict["api_key"],
237237
base_url=config_dict["base_url"].replace("/embeddings", ""),
238-
)
238+
),
239239
)
240240

241241
async def add_content(self, db_id: str, items: list[str], params: dict | None = None) -> list[dict]:

src/knowledge/utils/kb_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ def get_embedding_config(embed_info: dict) -> dict:
319319
"model": embed_info["name"],
320320
"api_key": os.getenv(embed_info["api_key"]) or embed_info["api_key"],
321321
"base_url": embed_info["base_url"],
322-
"dimension": embed_info.get("dimension", 1024)
322+
"dimension": embed_info.get("dimension", 1024),
323323
}
324324
logger.debug(f"Embedding config from dict: {config_dict}")
325325
return config_dict

0 commit comments

Comments
 (0)