All checks were successful
Build and Deploy Log Center / build-and-deploy (push) Successful in 2m16s
- 新增 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>
10 KiB
10 KiB
Log Center 改进方案:项目管理 + 修复失败追踪
背景
Log Center 当前存在三个核心问题:
- Repair Agent 无法识别项目仓库和本地路径 — 仓库地址(
repo_url)和本地项目路径(local_path)都硬编码在repair_agent/.env,需手动配置,且当前全部为空。应在接入日志收集时自动注册项目信息,并可在 Web 端统一管理。 - 修复失败原因未上报 —
ErrorLog表没有failure_reason字段;update_task_statusAPI 接收了message参数但直接丢弃(main.py:113);upload_report失败时原因静默丢失。 - 前端未展示失败原因 — BugList / BugDetail 页面无法看到修复失败的具体原因,用户必须逐一查看 RepairTask 记录才能找到。
第一部分:项目管理(仓库地址 + 本地路径 + Web 管理页)
1.1 新增 Project 数据模型
文件: app/models.py
class Project(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
project_id: str = Field(unique=True, index=True) # "rtc_backend"
name: Optional[str] = Field(default=None) # 显示名称
repo_url: Optional[str] = Field(default=None) # GitHub/Gitea 仓库地址
local_path: Optional[str] = Field(default=None) # 本地项目路径(Agent 修复时使用)
description: Optional[str] = Field(default=None) # 项目描述
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
新增 ProjectUpdate schema 用于编辑:
class ProjectUpdate(SQLModel):
name: Optional[str] = None
repo_url: Optional[str] = None
local_path: Optional[str] = None
description: Optional[str] = None
1.2 日志上报自动注册项目
文件: app/models.py — ErrorLogCreate 增加字段
class ErrorLogCreate(SQLModel):
# ... 现有字段 ...
repo_url: Optional[str] = None # 可选:上报时附带仓库地址
文件: app/main.py — report_log() 增加 upsert 逻辑
收到日志上报时:
- 根据
project_id查找 Project 记录 - 不存在 → 自动创建(
project_id+repo_url) - 已存在且
repo_url不为空 → 更新repo_url
向后兼容:不传
repo_url时仍正常创建 Project 记录(repo_url为空),后续可在 Web 端手动补充。
1.3 项目管理 API
文件: app/main.py
| 端点 | 方法 | 用途 |
|---|---|---|
GET /api/v1/projects |
GET | 项目列表(改造现有端点,从 Project 表查询,返回完整信息) |
GET /api/v1/projects/{project_id} |
GET | 获取单个项目详情(含 repo_url、local_path) |
PUT /api/v1/projects/{project_id} |
PUT | 编辑项目信息(repo_url、local_path、name、description) |
GET /api/v1/projects 响应示例
{
"projects": [
{
"id": 1,
"project_id": "rtc_backend",
"name": "RTC 后端",
"repo_url": "https://gitea.example.com/team/rtc_backend.git",
"local_path": "/Users/maidong/Desktop/zyc/qy_gitlab/rtc_backend",
"description": "Django 后端服务",
"created_at": "2026-01-15T08:00:00",
"updated_at": "2026-02-20T10:30:00"
}
]
}
PUT /api/v1/projects/{project_id} 请求示例
{
"name": "RTC 后端",
"repo_url": "https://gitea.example.com/team/rtc_backend.git",
"local_path": "/Users/maidong/Desktop/zyc/qy_gitlab/rtc_backend",
"description": "Django 后端服务"
}
1.4 Repair Agent 适配
task_manager.py — 新增 get_project_info()
def get_project_info(self, project_id: str) -> Optional[dict]:
"""从 Log Center API 获取项目配置(repo_url + local_path)"""
response = self.client.get(f"{self.base_url}/api/v1/projects/{project_id}")
return response.json() # { repo_url, local_path, ... }
core.py — 修改 fix_project() 和 fix_single_bug()
优先级链:
- local_path:API 返回值 →
settings.get_project_path()(.env) → 报错退出 - repo_url:API 返回值 →
settings.get_github_repo()(.env) → 跳过 Git 操作
# 获取项目配置(API 优先)
project_info = self.task_manager.get_project_info(project_id)
project_path = (project_info and project_info.get("local_path")) or settings.get_project_path(project_id)
github_repo = (project_info and project_info.get("repo_url")) or settings.get_github_repo(project_id)
1.5 Web 端项目管理页面
新增文件: web/src/pages/ProjectList.tsx
功能:
- 表格展示所有项目:project_id、名称、仓库地址、本地路径、描述、更新时间
- 行内编辑:点击「编辑」按钮进入编辑模式,可修改所有可编辑字段
- 状态指示:
repo_url/local_path为空时标红显示「未配置」 - 移动端适配:卡片式布局
修改文件: web/src/App.tsx
- 侧边栏新增「项目管理」入口(使用
FolderGit2图标) - 路由新增
/projects→ProjectList
修改文件: web/src/api.ts
export interface Project {
id: number;
project_id: string;
name: string | null;
repo_url: string | null;
local_path: string | null;
description: string | null;
created_at: string;
updated_at: string;
}
export const getProjectList = () =>
api.get<{ projects: Project[] }>('/api/v1/projects');
export const getProjectDetail = (projectId: string) =>
api.get<Project>(`/api/v1/projects/${projectId}`);
export const updateProject = (projectId: string, data: Partial<Project>) =>
api.put(`/api/v1/projects/${projectId}`, data);
1.6 数据库变更
-- 新建 Project 表
CREATE TABLE project (
id SERIAL PRIMARY KEY,
project_id VARCHAR UNIQUE NOT NULL,
name VARCHAR,
repo_url VARCHAR,
local_path VARCHAR,
description VARCHAR,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE UNIQUE INDEX ix_project_project_id ON project (project_id);
第二部分:修复失败原因录入数据库
2.1 ErrorLog 增加 failure_reason 字段
文件: app/models.py
class ErrorLog(SQLModel, table=True):
# ... 现有字段 ...
failure_reason: Optional[str] = Field(default=None, sa_column=Column(Text, nullable=True))
2.2 update_task_status API 存储 message
文件: app/main.py — update_task_status()
当前代码(第 113 行):
task.status = status_update.status
# We could log the message to a history table if needed ← message 被丢弃了
修改为:
task.status = status_update.status
if status_update.message and status_update.status == LogStatus.FIX_FAILED:
task.failure_reason = status_update.message
2.3 create_repair_report API 同步更新 ErrorLog
文件: app/main.py — create_repair_report()
当前仅在 FIXED / FIX_FAILED 时更新 ErrorLog 的 status。增加逻辑:
if error_log:
error_log.status = report.status
if report.failure_reason and report.status == LogStatus.FIX_FAILED:
error_log.failure_reason = report.failure_reason
session.add(error_log)
2.4 数据库变更
ALTER TABLE errorlog ADD COLUMN failure_reason TEXT;
第三部分:前端展示失败原因
3.1 TypeScript 类型更新
文件: web/src/api.ts
export interface ErrorLog {
// ... 现有字段 ...
failure_reason: string | null;
}
3.2 BugList 页面
文件: web/src/pages/BugList.tsx
当 bug 状态为 FIX_FAILED 时,在状态列旁或下方显示 failure_reason 摘要(超长截断)。
3.3 BugDetail 页面
文件: web/src/pages/BugDetail.tsx
当状态为 FIX_FAILED 且 failure_reason 不为空时,增加醒目的失败原因卡片:
{bug.failure_reason && (
<div className="card" style={{ borderLeft: '3px solid var(--error)' }}>
<h2><AlertTriangle size={16} /> 修复失败原因</h2>
<pre className="code-block error">{bug.failure_reason}</pre>
</div>
)}
3.4 RepairList 页面
文件: web/src/pages/RepairList.tsx
表格新增「失败原因」列,显示截断文本(text-overflow: ellipsis)。
文件变更清单
后端
| 文件 | 操作 | 说明 |
|---|---|---|
app/models.py |
修改 | 新增 Project + ProjectUpdate;ErrorLog 增加 failure_reason |
app/main.py |
修改 | 项目 CRUD API;修改 report_log / update_task_status / create_repair_report |
app/database.py |
修改 | 追加迁移 SQL(Project 表 + failure_reason 列) |
repair_agent/agent/task_manager.py |
修改 | 新增 get_project_info() |
repair_agent/agent/core.py |
修改 | fix_project / fix_single_bug 优先使用 API 配置 |
前端
| 文件 | 操作 | 说明 |
|---|---|---|
web/src/api.ts |
修改 | Project 类型 + API 函数;ErrorLog 增加 failure_reason |
web/src/App.tsx |
修改 | 路由 + 侧边栏增加「项目管理」 |
web/src/pages/ProjectList.tsx |
新增 | 项目列表 + 行内编辑 |
web/src/pages/BugList.tsx |
修改 | 展示 failure_reason |
web/src/pages/BugDetail.tsx |
修改 | 突出展示 failure_reason |
web/src/pages/RepairList.tsx |
修改 | 增加失败原因列 |
实施顺序
- 后端模型 — 新增 Project 模型 + ErrorLog 增加 failure_reason + 数据库迁移
- 后端 API — 项目 CRUD + 修改 report_log / update_task_status / create_repair_report
- Repair Agent — task_manager 获取项目配置 + core.py 优先使用 API 配置
- 前端 API 层 — api.ts 类型和函数更新
- 前端页面 — ProjectList 新页面 + BugList / BugDetail / RepairList 展示 failure_reason
- 路由 / 侧边栏 — App.tsx 接入项目管理入口
验证方式
- 调用
POST /api/v1/logs/report带repo_url→ 检查 Project 表自动创建 - Web 端「项目管理」页 → 编辑
repo_url/local_path→ 验证保存成功 - Repair Agent
status命令 → 验证读取到 API 配置的repo_url+local_path - 触发一次修复失败 → 检查
ErrorLog.failure_reason已写入 - Web 端 BugList / BugDetail / RepairList → 确认失败原因正确展示