審查結果: - P0 安全修復: sudo 密碼改用 secret ✅ - P1 識別: Sentry DSN build-arg 待處理 - P2 識別: 3 項次要問題已記錄 已更新: - Skills 01 v1.5: 前端建置禁止內網 IP - Skills 04 v2.1: CD 安全規範 + 內網 IP 禁令 - ADR-022: 新增前端內網 IP 禁令章節 - MEMORY.md: 新增審查記錄索引 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
175 lines
5.8 KiB
Markdown
175 lines
5.8 KiB
Markdown
# ADR-022: Sentry 整合架構
|
||
|
||
| 項目 | 內容 |
|
||
|------|------|
|
||
| **狀態** | ✅ 已採用 |
|
||
| **日期** | 2026-03-26 |
|
||
| **決策者** | 首席架構師 + 統帥 |
|
||
| **Phase** | Phase 10 |
|
||
|
||
## 背景
|
||
|
||
AWOOOI 需要完整的錯誤追蹤能力,補強 SignOz APM 的不足:
|
||
- SignOz 專注效能監控 (Traces, Metrics)
|
||
- Sentry 專注錯誤追蹤 (Stacktrace, Context, Session Replay)
|
||
|
||
## 決策
|
||
|
||
採用 **BFF + AI 分析** 三層架構:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ AWOOOI Web UI │
|
||
│ /errors 頁面 (React + next-intl) │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ AWOOOI API (BFF Layer) │
|
||
│ Router: /api/v1/errors/* │
|
||
│ Service: SentryService + ErrorAnalyzerService │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
┌───────────────┼───────────────┐
|
||
▼ ▼
|
||
┌──────────────────────┐ ┌──────────────────────────┐
|
||
│ Sentry Self-Hosted │ │ OpenClaw LLM │
|
||
│ 192.168.0.110:9000 │ │ 192.168.0.188:8088 │
|
||
└──────────────────────┘ └──────────────────────────┘
|
||
```
|
||
|
||
## 架構組件
|
||
|
||
### 1. SentryService (`services/sentry_service.py`)
|
||
|
||
**職責**: 封裝 Sentry API 呼叫
|
||
|
||
```python
|
||
class SentryService:
|
||
async def list_projects() -> list[dict]
|
||
async def list_issues(query, limit, cursor) -> list[dict]
|
||
async def get_issue(issue_id) -> dict
|
||
async def get_issue_events(issue_id, limit, full) -> list[dict]
|
||
async def get_project_stats(stat, resolution) -> list
|
||
def get_issue_url(issue_id) -> str
|
||
```
|
||
|
||
**設計原則**:
|
||
- Singleton 模式
|
||
- 配置從 `core/config.py` Settings 取得
|
||
- 支援 DI 測試替換
|
||
|
||
### 2. ErrorAnalyzerService (`services/error_analyzer_service.py`)
|
||
|
||
**職責**: AI 根因分析
|
||
|
||
```python
|
||
class ErrorAnalyzerService:
|
||
async def analyze_error(
|
||
issue_id, title, level, culprit,
|
||
count, stacktrace, context
|
||
) -> tuple[ErrorAnalysisResult | None, str, bool]
|
||
```
|
||
|
||
**分析結果**:
|
||
- root_cause: 根因分析
|
||
- category: CODE_BUG | DEPENDENCY | CONFIGURATION | ...
|
||
- severity: LOW | MEDIUM | HIGH | CRITICAL
|
||
- fix_recommendation: 修復建議
|
||
- prevention: 預防措施
|
||
- confidence: 信心度 (0.0-1.0)
|
||
|
||
### 3. Router Layer (`api/v1/errors.py`)
|
||
|
||
**職責**: HTTP 轉發 (符合 leWOOOgo 積木化)
|
||
|
||
| 端點 | 功能 |
|
||
|------|------|
|
||
| `GET /stats` | 錯誤統計概覽 |
|
||
| `GET /issues` | 列出 Issues (分頁、過濾) |
|
||
| `GET /issues/{id}` | Issue 詳情 |
|
||
| `GET /trends` | 趨勢圖表數據 |
|
||
| `POST /issues/{id}/analyze` | 觸發 AI 分析 |
|
||
|
||
## 配置管理
|
||
|
||
所有 Sentry 配置集中於 `core/config.py`:
|
||
|
||
```python
|
||
SENTRY_SELF_HOSTED_URL: str = "http://192.168.0.110:9000"
|
||
SENTRY_ORG: str = "sentry"
|
||
SENTRY_PROJECT: str = "awoooi-api"
|
||
SENTRY_AUTH_TOKEN: str = "" # K8s Secret
|
||
```
|
||
|
||
## 與 SignOz 的關係
|
||
|
||
| 工具 | 職責 | 查看時機 |
|
||
|------|------|----------|
|
||
| **SignOz** | APM + Traces | 慢、效能問題 |
|
||
| **Sentry** | Error Tracking | 壞、錯誤堆疊 |
|
||
|
||
**互補策略**: 兩者皆部署,各司其職。
|
||
|
||
## 前端整合
|
||
|
||
- 使用 `next-intl` 100% i18n (禁止 hardcode)
|
||
- Nothing.tech 視覺規範 (白底、細邊框、無陰影)
|
||
- React Hook: `useErrors()` 自動刷新 60 秒
|
||
|
||
## 替代方案 (已拒絕)
|
||
|
||
| 方案 | 拒絕原因 |
|
||
|------|----------|
|
||
| 直接嵌入 Sentry Iframe | 違反視覺主權,無法自訂 UI |
|
||
| 前端直接呼叫 Sentry API | 違反 BFF 原則,CORS 問題 |
|
||
| 只用 SignOz | 錯誤追蹤能力不足 |
|
||
|
||
## 後果
|
||
|
||
### 正面
|
||
- 完整的錯誤追蹤能力
|
||
- AI 輔助根因分析
|
||
- 符合 leWOOOgo 架構
|
||
|
||
### 負面
|
||
- 多一個服務需維護 (Sentry Self-Hosted)
|
||
- 額外的 API 呼叫延遲
|
||
|
||
## 🔴 前端內網 IP 禁令 (2026-03-30 補充)
|
||
|
||
### 問題
|
||
|
||
前端 Sentry DSN 使用內網 IP (`192.168.0.110:9000`) 會觸發瀏覽器「存取區域網路」權限對話框。
|
||
|
||
### 解決方案
|
||
|
||
**已採用**: Sentry Tunnel (方案 A)
|
||
|
||
```
|
||
前端 → /api/sentry-tunnel → Sentry Server (192.168.0.110:9000)
|
||
↑ 公網域名 ↑ Server-Side 內網
|
||
```
|
||
|
||
**配置位置**:
|
||
- `apps/web/src/app/api/sentry-tunnel/route.ts` - Tunnel 實作
|
||
- `apps/web/sentry.client.config.ts` - `tunnel: '/api/sentry-tunnel'`
|
||
|
||
### CD Pipeline 規範
|
||
|
||
```yaml
|
||
# ❌ 禁止 (即使有 Tunnel,也不應暴露內網 IP)
|
||
--build-arg NEXT_PUBLIC_SENTRY_DSN=http://...@192.168.0.110:9000/2
|
||
|
||
# ✅ 不設定 (依賴 Tunnel 機制)
|
||
# 或使用公網域名反向代理
|
||
```
|
||
|
||
## 相關文件
|
||
|
||
- `project_phase10_arch_review.md` - 架構審查報告
|
||
- `project_sentry_full_integration.md` - 整合計畫
|
||
- `feedback_sentry_local_network.md` - 區域網路權限問題
|
||
- ADR-005: BFF Architecture
|
||
- ADR-006: AI Fallback Strategy
|