日志系统说明
本文档帮助开发者了解 MJ-Studio 日志系统的设计原理和运作流程。
概述
MJ-Studio 的日志系统分为两个独立部分:
- 控制台日志:使用
console.log输出实时统计信息,用于开发调试 - HTTP 文件日志:使用 JSONL 格式记录完整的 HTTP 请求响应数据,用于问题追踪
两者相互独立,各司其职:
- 控制台日志关注实时统计(请求大小、耗时、token 用量)
- 文件日志关注完整数据(HTTP 请求响应的原始内容)
一、控制台日志
设计目标
实时监控系统运行状态,输出格式化的统计信息,方便开发者快速了解:
- 哪个对话/任务正在执行
- 使用了哪个上游和模型
- 请求响应的大小和耗时
- 是否发生错误
日志格式
对话模块
[Chat] {操作类型} | 对话#{id} "{标题}" | {详细信息}操作类型:聊天请求/完成、重放请求/完成、压缩请求/完成、标题请求/完成、错误、中断
示例:
[Chat] 聊天请求 | 对话#123 "Vue组件设计" | 上游:https://api.openai.com 模型:gpt-4 | 提示词:0.5KB 历史:10条/15.2KB 当前:0.3KB | 总计:16.0KB
[Chat] 聊天完成 | 对话#123 | 响应:2.1KB | 耗时:3250ms
[Chat] 聊天错误 | 对话#123 | HTTP 429: Rate limit exceeded绘图/视频任务
[Task] {操作} | #{taskId} {modelType}/{apiFormat} | 上游:{name} 模型:{modelName} Key:{keyName} | {详细信息}示例:
[Task] 提交 | #57 image/mj-proxy | 上游:MJ官方 模型:midjourney Key:default | 一只可爱的猫咪...
[Task] #57 HTTP 请求 → POST https://api.midjourney.com/mj/submit/imagine
[Task] #57 HTTP 响应 ← 200 OK (1234ms)数据统计
- 大小计算:UTF-8 编码字节数,< 1KB 显示字节,≥ 1KB 显示 KB(保留1位小数)
- 消息统计:格式为
{count}条/{size}KB - 耗时计算:请求开始到响应结束的毫秒数
实现位置
- 对话日志:
server/services/chat.ts、server/services/claude.ts - 任务日志:
server/services/task.ts及各上游服务文件
二、HTTP 文件日志
设计目标
记录完整的 API 请求响应数据,便于:
- 追踪具体的 API 调用细节
- 调试上游 API 返回的错误
- 分析接口性能问题
- 审计 API 调用历史
文件组织
logs/
├── conversation/
│ ├── 1.jsonl # 对话 #1 的所有请求响应
│ ├── 2.jsonl
│ └── ...
└── task/
├── 1.jsonl # 任务 #1 的所有请求响应
├── 2.jsonl
└── ...特点:
- 按对话 ID 或任务 ID 分文件
- JSONL 格式(每行一个 JSON 对象)
- 自动创建目录和文件
- 支持追加写入
JSONL 格式
JSONL (JSON Lines) 每行包含一个独立的 JSON 对象。
优势:
- 易于追加:直接写入文件末尾
- 易于读取:逐行解析,内存占用小
- 易于工具处理:
jq、grep等可直接处理
示例:
jsonl
{"type":"request","timestamp":"2025-01-06T10:30:00.000Z","messageId":123,"url":"https://api.openai.com/v1/chat/completions","method":"POST","headers":{"Authorization":"Bea...xyz"},"body":{"model":"gpt-4","messages":[...]}}
{"type":"response","timestamp":"2025-01-06T10:30:02.500Z","messageId":123,"status":200,"statusText":"OK","body":{"choices":[...]},"durationMs":2500}记录内容
请求记录
type:"request"timestamp: ISO 8601 格式时间戳conversationId/taskId: 关联 IDmessageId: (仅对话)消息 IDurl: 请求 URLmethod: HTTP 方法headers: 请求头(已脱敏)body: 请求体(已脱敏)
响应记录
type:"response"timestamp: ISO 8601 格式时间戳conversationId/taskId: 关联 IDmessageId: (仅对话)消息 IDstatus: HTTP 状态码statusText: HTTP 状态文本body: 响应体(已脱敏)durationMs: 请求耗时(毫秒)error/errorType: (仅错误)错误信息
数据脱敏规则
1. Authorization 头
显示首尾各 4 个字符,中间用省略号代替。
原始:Bearer sk-abc123def456ghi789jkl012mno345
脱敏:Bea...3452. Base64 图片数据
自动检测并截断为 [base64 N chars] 或 [dataUrl N chars]。
检测规则:
- Data URL 格式:
data:image/*;base64,... - 纯 Base64:连续 Base64 字符(长度 > 100)
3. 消息数组截断
对于大量消息的请求,保留前 2 条和最后 1 条,添加元数据。
json
{
"messages": {
"_truncated": true,
"_summary": "[10 messages, 15234 bytes]",
"_first": [
{"role": "system", "content": "你是一个专业的AI助手...长的AI助手,擅长写作 (245字节)"},
{"role": "user", "content": "你好,我想了解一下...下一下人工智能的发展 (189字节)"}
],
"_last": {"role": "user", "content": "帮我写一篇关于人...篇关于人工智能的文章 (156字节)"}
}
}4. 消息内容截断
单条消息 content 保留首尾各 20 字符。
规则:
- 长度 ≤ 50:保持原样
- 长度 > 50:首 20 + "..." + 尾 20 + " (N字节)"
原始:你是一个专业的AI助手,能够帮助用户解答各种问题...(省略)...你擅长写作、编程、分析数据等多种技能。
截断:你是一个专业的AI助手,能够帮助用...同时保持友好和专业的态度。你擅长写作、编程、分析数据等多种技能。 (245字节)5. 流式响应内容
记录首尾预览和总长度。
你好!我是 AI 助手...助和支持。有什么可以帮助您的吗? (总长度: 1234字节)记录时机
对话模块
- 请求发起时:记录完整 HTTP 请求
- 响应完成时:
- 成功:记录响应体、状态码、耗时
- 流式输出:记录内容预览
- HTTP 错误:记录完整错误响应体
- 网络错误:记录错误消息和类型
任务模块
- 提交任务时:记录请求
- 收到响应时:记录响应
- 轮询状态时:(可选)记录轮询请求响应
- 任务失败时:记录错误响应
实现位置
日志工具:server/utils/httpLogger.ts
日志函数:
logConversationRequest(conversationId, messageId, data)logConversationResponse(conversationId, messageId, data)logTaskRequest(taskId, data)logTaskResponse(taskId, data)
调用位置:
- 对话服务:
chat.ts、claude.ts - 任务服务:
mj.ts、gemini.ts、dalle.ts、openaiChat.ts、koukoutu.ts、videoUnified.ts
日志查看
bash
# 查看对话日志
cat logs/conversation/1.jsonl | jq .
# 筛选请求记录
cat logs/conversation/1.jsonl | jq 'select(.type == "request")'
# 筛选错误响应
cat logs/conversation/1.jsonl | jq 'select(.status >= 400)'
# 查看任务日志
cat logs/task/57.jsonl | jq .
# 查看最后一条记录
tail -n 1 logs/task/57.jsonl | jq .
# 搜索特定错误
grep "Rate limit" logs/**/*.jsonl三、运作流程
对话流程
用户发送消息
↓
API 端点接收 (server/api/conversations/[id]/messages.post.ts)
↓
准备日志上下文(conversationId、messageId、操作类型等)
↓
调用对话服务 (chat.ts 或 claude.ts)
↓
【控制台】输出"聊天请求"统计
【文件】记录 HTTP 请求到 logs/conversation/{id}.jsonl
↓
发起上游 API 请求
↓
接收响应
↓
【控制台】输出"聊天完成"统计
【文件】记录响应到 logs/conversation/{id}.jsonl
↓
返回结果给前端绘图任务流程
用户提交绘图任务
↓
API 端点接收 (server/api/tasks.post.ts)
↓
创建任务记录(保存到数据库)
↓
调用任务服务 submitTask(taskId)
↓
【控制台】输出"提交"统计
↓
根据 apiFormat 选择上游服务
↓
【文件】记录 HTTP 请求到 logs/task/{taskId}.jsonl
【控制台】输出"HTTP 请求"
↓
发起上游 API 请求
↓
【文件】记录响应到 logs/task/{taskId}.jsonl
【控制台】输出"HTTP 响应"
↓
更新任务状态异步轮询流程(MJ、抠抠图、视频)
提交任务(同上)
↓
收到上游任务 ID
↓
更新任务状态为"processing"
↓
前端定时轮询 (GET /api/tasks/{id})
↓
后端调用 syncTaskStatus(taskId)
↓
查询上游任务状态
↓
【文件】记录轮询请求响应(可选)
↓
更新本地任务状态
↓
返回最新状态给前端四、设计原则
1. 职责分离
- 控制台日志:实时监控和开发调试
- 文件日志:完整数据记录和事后分析
2. 数据隐私
- 自动脱敏敏感信息
- 保留必要的调试信息
- 可追溯但不泄露完整数据
3. 性能考虑
- 追加写入,避免锁定文件
- JSONL 流式处理,内存占用小
- 自动截断大数据
4. 可维护性
- 日志格式统一
- 按对话/任务分文件
- 元数据标记提示数据处理
五、常见场景
调试对话请求失败
- 查看控制台日志确认错误
- 打开
logs/conversation/{id}.jsonl - 找到最近的请求响应记录
- 检查请求体和响应体
分析任务耗时
- 查看控制台"HTTP 响应"耗时
- 打开
logs/task/{taskId}.jsonl - 查看
durationMs字段 - 对比不同模型平均耗时
追踪 API Key 使用
- 搜索日志中的 Authorization 头
- 根据首尾字符识别不同 Key
- 统计使用次数和错误率
六、注意事项
开发时
- 修改服务时传递正确的日志参数
- 新增上游服务时记录日志
- 测试时检查日志文件生成
部署时
- 确保
logs/目录可写 - 定期清理旧日志
- 监控日志文件大小
调试时
- 优先查看控制台日志
- 需要详细数据时查看文件日志
- 注意脱敏数据
七、扩展方向
- 日志聚合:集成 Elasticsearch、Loki 等
- 日志分析:统计调用频率、成功率、平均耗时
- 告警机制:错误率、余额、耗时异常告警
- 日志压缩:自动压缩旧日志节省空间
通过理解日志系统的设计和运作流程,开发者可以更高效地调试问题、优化性能和监控系统健康状况。
