docs: 管理文档位置

This commit is contained in:
SuperManTouX 2026-03-06 10:44:03 +08:00
parent 4713cde2a8
commit 59818f7d7c
4 changed files with 150 additions and 406 deletions

View File

@ -1,151 +1,151 @@
# 统一日志管理系统说明 # 统一日志管理系统说明
## 功能特性 ## 功能特性
1. **多级别日志支持**DEBUG, INFO, WARNING, ERROR, CRITICAL 1. **多级别日志支持**DEBUG, INFO, WARNING, ERROR, CRITICAL
2. **结构化日志**支持JSON格式的结构化日志输出 2. **结构化日志**支持JSON格式的结构化日志输出
3. **文件轮转**:自动按日期和大小分割日志文件 3. **文件轮转**:自动按日期和大小分割日志文件
4. **系统监控**:记录系统状态和性能指标 4. **系统监控**:记录系统状态和性能指标
5. **请求追踪**记录API请求和响应信息 5. **请求追踪**记录API请求和响应信息
6. **错误追踪**:详细记录异常和错误信息 6. **错误追踪**:详细记录异常和错误信息
## 使用方法 ## 使用方法
### 1. 基本日志记录 ### 1. 基本日志记录
```python ```python
from utils.logger import log_debug, log_info, log_warning, log_error, log_critical from utils.logger import log_debug, log_info, log_warning, log_error, log_critical
log_info("服务启动成功") log_info("服务启动成功")
log_warning("内存使用率较高") log_warning("内存使用率较高")
log_error("API请求失败") log_error("API请求失败")
``` ```
### 2. 结构化日志 ### 2. 结构化日志
```python ```python
from utils.logger import log_structured from utils.logger import log_structured
log_structured( log_structured(
"info", "info",
"用户登录成功", "用户登录成功",
user_id="12345", user_id="12345",
ip_address="192.168.1.100", ip_address="192.168.1.100",
timestamp=datetime.now().isoformat() timestamp=datetime.now().isoformat()
) )
``` ```
### 3. 请求日志 ### 3. 请求日志
```python ```python
from utils.logger import log_request_info, log_response_info from utils.logger import log_request_info, log_response_info
log_request_info("POST", "/api/chat", "192.168.1.100", "Mozilla/5.0...") log_request_info("POST", "/api/chat", "192.168.1.100", "Mozilla/5.0...")
log_response_info(200, 150.5, "/api/chat", "POST", "192.168.1.100") log_response_info(200, 150.5, "/api/chat", "POST", "192.168.1.100")
``` ```
### 4. 错误详情记录 ### 4. 错误详情记录
```python ```python
from utils.logger import log_error_detail from utils.logger import log_error_detail
try: try:
# 可能出错的代码 # 可能出错的代码
pass pass
except Exception as e: except Exception as e:
log_error_detail( log_error_detail(
type(e).__name__, type(e).__name__,
str(e), str(e),
str(e.__traceback__), str(e.__traceback__),
context={"user_id": "123", "action": "chat_request"} context={"user_id": "123", "action": "chat_request"}
) )
``` ```
### 5. 对话交互记录 ### 5. 对话交互记录
```python ```python
from utils.logger import log_chat_interaction from utils.logger import log_chat_interaction
log_chat_interaction( log_chat_interaction(
user_input="你好,请帮我分析这张图片", user_input="你好,请帮我分析这张图片",
ai_response="这张图片显示了一座山和一片湖泊", ai_response="这张图片显示了一座山和一片湖泊",
model="qwen-vl-plus", model="qwen-vl-plus",
conversation_id="conv_abc123" conversation_id="conv_abc123"
) )
``` ```
### 6. 系统状态记录 ### 6. 系统状态记录
```python ```python
from utils.logger import log_system_status from utils.logger import log_system_status
log_system_status( log_system_status(
status="healthy", status="healthy",
uptime=3600.5, uptime=3600.5,
cpu_usage=45.2, cpu_usage=45.2,
memory_usage=60.8, memory_usage=60.8,
disk_usage=75.1 disk_usage=75.1
) )
``` ```
## 配置 ## 配置
### 环境变量配置 ### 环境变量配置
| 环境变量 | 默认值 | 说明 | | 环境变量 | 默认值 | 说明 |
|---------|--------|------| |---------|--------|------|
| LOG_LEVEL | INFO | 日志级别 | | LOG_LEVEL | INFO | 日志级别 |
| LOG_DIR | logs | 日志文件目录 | | LOG_DIR | logs | 日志文件目录 |
| LOG_MAX_BYTES | 10485760 | 单个日志文件最大大小 | | LOG_MAX_BYTES | 10485760 | 单个日志文件最大大小 |
| LOG_BACKUP_COUNT | 5 | 保留的备份日志数量 | | LOG_BACKUP_COUNT | 5 | 保留的备份日志数量 |
### 配置文件 ### 配置文件
创建 `logging.conf` 文件来配置日志系统: 创建 `logging.conf` 文件来配置日志系统:
``` ```
LOG_LEVEL=INFO LOG_LEVEL=INFO
LOG_DIR=logs LOG_DIR=logs
LOG_MAX_BYTES=10485760 LOG_MAX_BYTES=10485760
LOG_BACKUP_COUNT=5 LOG_BACKUP_COUNT=5
``` ```
## 日志文件组织 ## 日志文件组织
- 日志文件按日期分割:`ai-chat-api_2026-03-03.log` - 日志文件按日期分割:`ai-chat-api_2026-03-03.log`
- 自动轮转,当日志文件达到指定大小时创建新文件 - 自动轮转,当日志文件达到指定大小时创建新文件
- 保留最近5个日志文件旧文件会被自动删除 - 保留最近5个日志文件旧文件会被自动删除
- 日志文件存放在 `logs/` 目录下 - 日志文件存放在 `logs/` 目录下
## 集成到现有代码 ## 集成到现有代码
在你的 FastAPI 应用中: 在你的 FastAPI 应用中:
```python ```python
from utils.logger import setup_global_logger from utils.logger import setup_global_logger
# 初始化日志系统 # 初始化日志系统
logger = setup_global_logger() logger = setup_global_logger()
@app.middleware("http") @app.middleware("http")
async def logging_middleware(request, call_next): async def logging_middleware(request, call_next):
start_time = time.time() start_time = time.time()
# 记录请求 # 记录请求
logger.info(f"Request: {request.method} {request.url.path}") logger.info(f"Request: {request.method} {request.url.path}")
response = await call_next(request) response = await call_next(request)
# 记录响应 # 记录响应
process_time = time.time() - start_time process_time = time.time() - start_time
logger.info(f"Response: {response.status_code} in {process_time:.2f}s") logger.info(f"Response: {response.status_code} in {process_time:.2f}s")
return response return response
``` ```
## 注意事项 ## 注意事项
1. 使用结构化日志便于日志分析和查询 1. 使用结构化日志便于日志分析和查询
2. 避免在日志中记录敏感信息如密码、token等 2. 避免在日志中记录敏感信息如密码、token等
3. 适当使用日志级别避免过度记录DEBUG信息 3. 适当使用日志级别避免过度记录DEBUG信息
4. 定期清理旧的日志文件,防止磁盘空间不足 4. 定期清理旧的日志文件,防止磁盘空间不足

View File

@ -1,37 +0,0 @@
<div className={styles.chooseModel}>
<Select className="choose-model"
onChange={(value) => chooseModel(value)}
options={modelOptionList}
style={{
width: "100%",
border: "none",
borderRadius: "10px",
}}
value={currentModel?.value}
/>
{/* <Button style={{float:"right",marginLeft:"auto"}}
type="text"
icon={menuCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
onClick={toggleMenuCollapsed}
/> */}
</div>
<Button
key={item?.key}
onClick={handleNewChat}
type="primary"
className={styles.functionMenuItem}
icon={<PlusOutlined />}
block
>
新对话
</Button>
.choose-model .ant-select-selector {
border: none !important;
background-color: #f3f4f5 !important;
box-shadow: none !important;
border-radius: 10px !important;
}

View File

@ -1,219 +0,0 @@
import { createStyles } from "antd-style";
export const useStyle = createStyles(({ token, css }) => {
return {
menuCollapsed: css`
width: 0;
min-width: 0;
padding: 0;
overflow: hidden;
text-overflow: ellipsis;
display: none;
transform: translateX(-999px);
.functionMenu,
.chooseModel,
.conversationsContainer {
display: none;
}
`,
menu: css`
background: #fff;
max-width: 320px;
min-width: 280px;
width: 320px;
height: 100%;
display: flex;
flex-direction: column;
margin: 0 15px 0 0;
padding: 0 20px;
border-radius: 15px;
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
transition: width 0.8s ease-in-out;
`,
userProfile: css`
display: flex;
height: 30px;
width: 100%;
justify-content: flex-start;
gap: 168px;
align-items: center;
padding: 16px 0 16px 8px;
border-bottom: 1px solid ${token.colorBorderSecondary};
margin-bottom: 16px;
img {
height: 88px;
width: 88px;
object-fit: contain;
}
`,
logoClickable: css`
cursor: pointer;
transition: all 0.2s ease-in-out;
border-radius: 4px;
padding: 2px;
&:hover {
background-color: ${token.colorBgTextHover};
transform: scale(1.05);
}
&:active {
transform: scale(0.95);
}
`,
functionMenu: css`
display: flex;
flex-direction: column;
width: 100%;
gap: 8px;
margin-bottom: 8px;
padding: 10px 0;
`,
functionMenuItem: css`
padding: 10px 20px;
cursor: pointer;
border-radius: 10px;
transition: all 0.2s;
background-color: #f3f4f5 !important;
box-shadow: none !important;
color: #000F33 !important;
&:hover {
background-color: #000F33 !important;
color: #ffffff !important;
}
.anticon {
font-size: 14px;
margin-right: 0px;
}
span {
font-size: 14px;
}
`,
chooseModel: css`
padding-top: 15px;
display: flex;
// flex-direction: column;
color: rgba(0, 0, 0, 0.88);
margin: 0 0 12px;
gap: 8px;
justify-content: space-between;
align-items: center;
gap: 8px;
`,
conversationsContainer: css`
display: flex;
flex-direction: column;
gap: 8px;
flex: 1;
overflow: hidden;
position: relative;
`,
conversationsScrollContainer: css`
height: 100%;
overflow: auto;
padding-right: 2px;
margin-bottom: 48px;
`,
conversationItem: css`
display: flex;
align-items: center;
padding: 8px 12px;
margin: 2px 0;
cursor: pointer;
border-radius: 10px;
transition: background-color 0.2s ease;
&:hover {
background-color: ${token.colorBgTextHover};
}
&.active {
background-color: #EBF0FC;
}
`,
conversationTitle: css`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 15px;
flex: 1;
`,
actionButtonsContainer: css`
display: flex;
gap: 4px;
visibility: hidden;
.active & {
visibility: visible;
}
.conversationItem:hover & {
visibility: visible;
}
`,
editButton: css`
&.ant-btn {
padding: 0;
width: 24px;
height: 24px;
}
`,
deleteButton: css`
&.ant-btn {
padding: 0;
width: 24px;
height: 24px;
}
`,
titleEditContainer: css`
display: flex;
align-items: center;
width: 100%;
gap: 4px;
`,
titleInput: css`
flex: 1;
font-size: 15px;
`,
titleEditButton: css`
padding: 0 4px;
font-size: 16px;
height: 22px;
min-width: 22px;
`,
collapsedMenuBtn: css`
position: fixed;
top: 12px;
left: 12px;
z-index: 1000;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: ${token.boxShadowSecondary};
cursor: pointer;
opacity: 1;
transform: scale(1);
&:hover {
transform: scale(1.05);
}
`,
bottomLinkWrapper: css`
position: absolute;
left: 20px;
bottom: 8px;
z-index: 10;
`,
menuTitle: css`
color: ${token.colorTextTertiary};
font-size: 14px;
`,
};
});