log-center/docs/integration_guide.md
zyc 625e53dc44
All checks were successful
Build and Deploy Log Center / build-and-deploy (push) Successful in 2m16s
feat(project-mgmt): 项目管理 + 失败原因追踪 + 前端展示
- 新增 Project 模型(repo_url, local_path, name, description)
- 项目 CRUD API(GET/PUT /api/v1/projects)
- 日志上报自动 upsert Project 记录
- ErrorLog 增加 failure_reason 字段
- update_task_status / create_repair_report 写入失败原因
- Repair Agent 优先从 API 获取项目配置,回退 .env
- 新增 Web 端「项目管理」页面(表格 + 行内编辑)
- BugList/BugDetail/RepairList 展示失败原因
- 更新接入指南文档

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 11:18:27 +08:00

458 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Log Center 接入指南
## 概述
Log Center 是一个集中式错误日志收集与 AI 自动修复平台,提供 REST API 供各项目接入,实现运行时错误的统一收集、去重、追踪、分析和自动修复。
接入流程:
1. 项目首次上报日志时自动注册到 Log Center
2. 在 Web 管理端配置项目的**仓库地址**和**本地路径**
3. Repair Agent 根据配置自动拉取代码并修复 Bug
---
## 快速开始
### 服务地址
| 环境 | API 地址 | 仪表盘 |
|------|----------|--------|
| 本地开发 | `http://localhost:8002` | `http://localhost:8003` |
| 生产环境 | `https://qiyuan-log-center-api.airlabs.art` | `https://qiyuan-log-center.airlabs.art` |
---
## API 接口
### 上报错误日志
**POST** `/api/v1/logs/report`
#### 请求体 (JSON)
```json
{
"project_id": "rtc_backend",
"environment": "production",
"level": "ERROR",
"timestamp": "2026-01-30T10:30:00Z",
"version": "1.2.3",
"commit_hash": "abc1234",
"repo_url": "https://gitea.example.com/team/rtc_backend.git",
"error": {
"type": "ValueError",
"message": "invalid literal for int() with base 10: 'abc'",
"file_path": "apps/users/views.py",
"line_number": 42,
"stack_trace": [
"Traceback (most recent call last):",
" File \"apps/users/views.py\", line 42, in get_user",
" user_id = int(request.GET['id'])",
"ValueError: invalid literal for int() with base 10: 'abc'"
]
},
"context": {
"url": "/api/users/123",
"method": "GET",
"user_id": "u_12345",
"request_id": "req_abc123"
}
}
```
#### 字段说明
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `project_id` | string | ✅ | 项目标识,如 `rtc_backend`, `rtc_web`, `airhub_app` |
| `environment` | string | ✅ | 环境:`development`, `staging`, `production` |
| `level` | string | ✅ | 日志级别:`ERROR`, `WARNING`, `CRITICAL` |
| `source` | string | ❌ | 来源:`runtime`(默认), `cicd`, `deployment` |
| `timestamp` | string | ❌ | ISO 8601 格式,不传则使用服务器时间 |
| `version` | string | ❌ | 应用版本号 |
| `commit_hash` | string | ❌ | Git commit hash |
| `repo_url` | string | ❌ | 项目仓库地址,首次上报时传入可自动关联到项目 |
| `error.type` | string | ✅ | 异常类型,如 `ValueError`, `TypeError` |
| `error.message` | string | ✅ | 错误消息 |
| `error.file_path` | string | ❌ | 出错文件路径runtime 必填cicd/deployment 可选) |
| `error.line_number` | int | ❌ | 出错行号runtime 必填cicd/deployment 可选) |
| `error.stack_trace` | array | ✅ | 堆栈信息(数组或字符串) |
| `context` | object | ❌ | 额外上下文信息URL、用户ID等 |
> **项目自动注册**: 首次上报日志时,系统会根据 `project_id` 自动创建项目记录。如果同时传入 `repo_url`,会自动关联仓库地址,供 Repair Agent 使用。
#### 响应
**成功 (200)**
```json
{
"message": "Log reported",
"id": 123
}
```
**已存在 (200)** - 重复错误自动去重
```json
{
"message": "Log deduplicated",
"id": 123,
"status": "NEW"
}
```
---
### 项目管理 API
项目在首次日志上报时自动创建,之后可通过 API 或 Web 管理端编辑配置。
#### 获取项目列表
**GET** `/api/v1/projects`
```json
{
"projects": [
{
"id": 1,
"project_id": "rtc_backend",
"name": "RTC 后端",
"repo_url": "https://gitea.example.com/team/rtc_backend.git",
"local_path": "/home/dev/projects/rtc_backend",
"description": "Django 后端服务",
"created_at": "2026-01-15T08:00:00",
"updated_at": "2026-02-20T10:30:00"
}
]
}
```
#### 获取项目详情
**GET** `/api/v1/projects/{project_id}`
返回单个项目的完整信息。
#### 编辑项目配置
**PUT** `/api/v1/projects/{project_id}`
```json
{
"name": "RTC 后端",
"repo_url": "https://gitea.example.com/team/rtc_backend.git",
"local_path": "/home/dev/projects/rtc_backend",
"description": "Django 后端服务"
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `name` | string | 项目显示名称 |
| `repo_url` | string | Git 仓库地址Repair Agent 克隆/推送代码用) |
| `local_path` | string | 本地项目路径Repair Agent 在此目录执行修复) |
| `description` | string | 项目描述 |
> **注意**: `repo_url` 和 `local_path` 是 Repair Agent 正常工作的关键配置。未配置时 Agent 将无法执行 Git 操作或定位项目代码。可在 Web 管理端的「项目管理」页面中配置。
---
## 接入示例
### Python (Django / FastAPI)
```python
import requests
import traceback
import os
LOG_CENTER_URL = os.getenv("LOG_CENTER_URL", "http://localhost:8002")
def report_error(exc, context=None):
"""上报错误到 Log Center"""
tb = traceback.extract_tb(exc.__traceback__)
last_frame = tb[-1] if tb else None
payload = {
"project_id": "rtc_backend",
"environment": os.getenv("ENVIRONMENT", "development"),
"level": "ERROR",
"repo_url": os.getenv("REPO_URL", ""), # 可选:关联仓库地址
"error": {
"type": type(exc).__name__,
"message": str(exc),
"file_path": last_frame.filename if last_frame else "unknown",
"line_number": last_frame.lineno if last_frame else 0,
"stack_trace": traceback.format_exception(exc)
},
"context": context or {}
}
try:
requests.post(
f"{LOG_CENTER_URL}/api/v1/logs/report",
json=payload,
timeout=3 # 快速失败,不影响主业务
)
except Exception:
pass # 静默失败,不影响主业务
```
#### Django 集成位置
修改 `utils/exceptions.py``custom_exception_handler`:
```python
def custom_exception_handler(exc, context):
# 上报到 Log Center (异步,不阻塞响应)
report_error(exc, {
"view": str(context.get("view")),
"request_path": context.get("request").path if context.get("request") else None,
})
# ... 原有逻辑不变 ...
```
---
### JavaScript / TypeScript (React / Vue)
```typescript
const LOG_CENTER_URL = import.meta.env.VITE_LOG_CENTER_URL || 'http://localhost:8002';
interface ErrorPayload {
project_id: string;
environment: string;
level: string;
repo_url?: string;
error: {
type: string;
message: string;
file_path: string;
line_number: number;
stack_trace: string[];
};
context?: Record<string, unknown>;
}
export function reportError(error: Error, context?: Record<string, unknown>) {
// 解析堆栈信息
const stackLines = error.stack?.split('\n') || [];
const match = stackLines[1]?.match(/at\s+.*\s+\((.+):(\d+):\d+\)/);
const payload: ErrorPayload = {
project_id: 'rtc_web',
environment: import.meta.env.MODE,
level: 'ERROR',
error: {
type: error.name,
message: error.message,
file_path: match?.[1] || 'unknown',
line_number: parseInt(match?.[2] || '0'),
stack_trace: stackLines,
},
context: {
url: window.location.href,
userAgent: navigator.userAgent,
...context,
},
};
// 使用 sendBeacon 确保页面关闭时也能发送
if (navigator.sendBeacon) {
navigator.sendBeacon(
`${LOG_CENTER_URL}/api/v1/logs/report`,
JSON.stringify(payload)
);
} else {
fetch(`${LOG_CENTER_URL}/api/v1/logs/report`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
keepalive: true,
}).catch(() => {});
}
}
```
#### Axios 拦截器集成
修改 `src/api/request.ts`:
```typescript
request.interceptors.response.use(
(response) => { /* ... */ },
(error: AxiosError) => {
// 上报到 Log Center
reportError(error, {
url: error.config?.url,
method: error.config?.method,
status: error.response?.status,
});
// ... 原有逻辑不变 ...
}
);
```
---
### Flutter (Dart)
```dart
import 'dart:convert';
import 'package:http/http.dart' as http;
const logCenterUrl = String.fromEnvironment(
'LOG_CENTER_URL',
defaultValue: 'http://localhost:8002',
);
Future<void> reportError(dynamic error, StackTrace stackTrace, {Map<String, dynamic>? context}) async {
final stackLines = stackTrace.toString().split('\n');
// 解析第一行获取文件和行号
final match = RegExp(r'#0\s+.*\((.+):(\d+):\d+\)').firstMatch(stackLines.first);
final payload = {
'project_id': 'airhub_app',
'environment': const String.fromEnvironment('ENVIRONMENT', defaultValue: 'development'),
'level': 'ERROR',
'repo_url': 'https://gitea.example.com/team/airhub_app.git',
'error': {
'type': error.runtimeType.toString(),
'message': error.toString(),
'file_path': match?.group(1) ?? 'unknown',
'line_number': int.tryParse(match?.group(2) ?? '0') ?? 0,
'stack_trace': stackLines.take(20).toList(),
},
'context': context ?? {},
};
try {
await http.post(
Uri.parse('$logCenterUrl/api/v1/logs/report'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(payload),
).timeout(const Duration(seconds: 3));
} catch (_) {
// 静默失败
}
}
```
`main.dart` 中全局捕获:
```dart
void main() {
FlutterError.onError = (details) {
reportError(details.exception, details.stack ?? StackTrace.current);
};
runZonedGuarded(() {
runApp(const MyApp());
}, (error, stack) {
reportError(error, stack);
});
}
```
---
## 错误去重机制
Log Center 使用 **指纹(fingerprint)** 对错误进行去重,按来源使用不同的指纹策略:
| 来源 | 指纹组成 |
|------|----------|
| `runtime` | `MD5(project_id \| error_type \| file_path \| line_number)` |
| `cicd` | `MD5(project_id \| cicd \| error_type \| job_name \| step_name)` |
| `deployment` | `MD5(project_id \| deployment \| error_type \| namespace \| deployment_name)` |
相同指纹的错误只会记录一次。如果已修复的错误再次出现,系统会自动重新打开(回归检测)。
---
## 错误状态流转
```
NEW → VERIFYING → PENDING_FIX → FIXING → FIXED → VERIFIED → DEPLOYED
↓ ↓
CANNOT_REPRODUCE FIX_FAILED
```
| 状态 | 说明 |
|------|------|
| `NEW` | 新上报的错误 |
| `VERIFYING` | 正在验证复现 |
| `CANNOT_REPRODUCE` | 无法复现 |
| `PENDING_FIX` | 等待修复 |
| `FIXING` | AI Agent 正在修复中 |
| `FIXED` | 已修复,待验证 |
| `VERIFIED` | 已验证修复 |
| `DEPLOYED` | 已部署上线 |
| `FIX_FAILED` | 修复失败(失败原因会记录到数据库并在 Web 端展示) |
---
## Web 管理端
### 项目管理
访问 Web 管理端的「项目管理」页面,可以:
- 查看所有已注册项目及其配置状态
- 编辑项目的**仓库地址**`repo_url`)和**本地路径**`local_path`
- 未配置的字段会标红提示
> Repair Agent 依赖这两个配置来定位项目代码和执行 Git 操作。请确保在接入后及时配置。
### 缺陷追踪
- **缺陷列表**: 按项目、来源、状态筛选,修复失败的缺陷会直接显示失败原因
- **缺陷详情**: 查看完整错误信息、堆栈、上下文,以及修复历史记录
- **修复报告**: 查看每轮 AI 修复的详细过程(分析、代码变更、测试结果、失败原因)
---
## 最佳实践
1. **首次接入时传入 `repo_url`**: 在日志上报中包含仓库地址,省去手动配置步骤
2. **设置超时**: 上报请求设置 3 秒超时,避免影响主业务
3. **静默失败**: 上报失败不应影响用户体验
4. **异步上报**: 使用异步方式上报,不阻塞主流程
5. **添加上下文**: 尽量添加有用的上下文信息用户ID、请求URL等
6. **环境区分**: 正确设置 `environment` 字段区分开发/生产
7. **配置本地路径**: 接入后在 Web 端配置 `local_path`,使 Repair Agent 能正确定位代码
---
## 环境变量配置
### Python 项目
```bash
# .env
LOG_CENTER_URL=http://localhost:8002
ENVIRONMENT=development
REPO_URL=https://gitea.example.com/team/rtc_backend.git # 可选
```
### JavaScript 项目
```bash
# .env
VITE_LOG_CENTER_URL=http://localhost:8002
```
### Flutter 项目
```bash
# 编译时传入
flutter run --dart-define=LOG_CENTER_URL=http://localhost:8002
flutter run --dart-define=ENVIRONMENT=development
```
---
## API 文档
完整 API 文档请访问: [http://localhost:8002/docs](http://localhost:8002/docs)