docs: 管理文档位置
This commit is contained in:
parent
4713cde2a8
commit
59818f7d7c
|
|
@ -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. 定期清理旧的日志文件,防止磁盘空间不足
|
||||||
37
need-1.txt
37
need-1.txt
|
|
@ -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;
|
|
||||||
}
|
|
||||||
219
need-style.ts
219
need-style.ts
|
|
@ -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;
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
Loading…
Reference in New Issue