feat(api): Phase 13 智能路由 + CI/CD 整合 (#74-88)
Phase 13.1 CI/CD Integration: - #76 workflow_run handler for CI failure diagnosis - #77 SignOz log query (query_logs, error_logs_summary MCP) - #78 CIAutoRepairService with risk-based execution decisions Phase 13.3 Smart Routing: - #85 Intent Classifier v2.0 (rule engine + LLM fallback) - #86 Complexity Scorer (9-dimension scoring) - #87 AI Router v3.0 (routing decision matrix) - #88 Token Counter (OTEL + Langfuse integration) New files: - services/ci_auto_repair.py (risk stratification) - services/model_registry.py (centralized model config) - services/token_counter.py (677 lines) - Skill 08: Model Router Expert - Skill 09: Strangler Pattern Expert - ADR-023: Smart Routing Architecture - ADR-024: API Layer Architecture Tests: - phase11-conversational.spec.ts (E2E tests) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,10 +6,17 @@ SignOz MCP Tool Provider - ADR-015 模組化架構
|
||||
- gold_metrics: 取得 Gold Metrics (RPS, Error Rate, P99)
|
||||
- trace_url: 生成 Trace 查詢 URL
|
||||
- system_metrics: 取得系統指標 (CPU/Disk)
|
||||
- query_logs: 查詢日誌 (Phase 13.1 #77)
|
||||
- error_logs_summary: 錯誤日誌摘要 (Phase 13.1 #77)
|
||||
|
||||
透過 DI 注入 SignOzClient,不直接 import services。
|
||||
|
||||
@see docs/adr/ADR-015-mcp-modular-architecture.md
|
||||
|
||||
版本: v1.1
|
||||
最後修改: 2026-03-26 16:45 (台北時區)
|
||||
修改者: Claude Code
|
||||
變更: Phase 13.1 #77 新增 query_logs, error_logs_summary
|
||||
"""
|
||||
|
||||
import uuid
|
||||
@@ -84,6 +91,34 @@ class SignOzProvider(MCPToolProvider):
|
||||
},
|
||||
server_name=self.name,
|
||||
),
|
||||
MCPTool(
|
||||
name="query_logs",
|
||||
description="Query logs from SignOz (Phase 13.1 #77). Use for CI failure diagnosis or service debugging.",
|
||||
input_schema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"service_name": {"type": "string", "description": "Service name (e.g., awoooi-api, awoooi-worker)"},
|
||||
"severity": {"type": "string", "description": "Log severity filter (ERROR, WARN, INFO, DEBUG). Comma-separated for multiple."},
|
||||
"search_text": {"type": "string", "description": "Text to search in log messages"},
|
||||
"time_window_minutes": {"type": "integer", "description": "Time window in minutes (default: 30)"},
|
||||
"limit": {"type": "integer", "description": "Max logs to return (default: 100)"},
|
||||
},
|
||||
},
|
||||
server_name=self.name,
|
||||
),
|
||||
MCPTool(
|
||||
name="error_logs_summary",
|
||||
description="Get error logs summary with counts and sample messages. Useful for quick diagnosis.",
|
||||
input_schema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"service_name": {"type": "string", "description": "Service name (required)"},
|
||||
"time_window_minutes": {"type": "integer", "description": "Time window (default: 60)"},
|
||||
},
|
||||
"required": ["service_name"],
|
||||
},
|
||||
server_name=self.name,
|
||||
),
|
||||
]
|
||||
|
||||
async def execute(
|
||||
@@ -101,6 +136,10 @@ class SignOzProvider(MCPToolProvider):
|
||||
output = self._trace_url(client, parameters)
|
||||
elif tool_name == "system_metrics":
|
||||
output = await self._system_metrics(client, parameters)
|
||||
elif tool_name == "query_logs":
|
||||
output = await self._query_logs(client, parameters)
|
||||
elif tool_name == "error_logs_summary":
|
||||
output = await self._error_logs_summary(client, parameters)
|
||||
else:
|
||||
return MCPToolResult(
|
||||
success=False,
|
||||
@@ -184,6 +223,48 @@ class SignOzProvider(MCPToolProvider):
|
||||
"time_range": metrics.get("time_range", {}),
|
||||
}
|
||||
|
||||
async def _query_logs(self, client, parameters: dict) -> dict:
|
||||
"""Query logs from SignOz (Phase 13.1 #77)"""
|
||||
service_name = parameters.get("service_name")
|
||||
severity = parameters.get("severity")
|
||||
search_text = parameters.get("search_text")
|
||||
time_window = parameters.get("time_window_minutes", 30)
|
||||
limit = parameters.get("limit", 100)
|
||||
|
||||
logs = await client.get_logs(
|
||||
service_name=service_name,
|
||||
severity=severity,
|
||||
search_text=search_text,
|
||||
time_window_minutes=time_window,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
return {
|
||||
"logs": logs,
|
||||
"count": len(logs),
|
||||
"filters": {
|
||||
"service_name": service_name,
|
||||
"severity": severity,
|
||||
"search_text": search_text,
|
||||
"time_window_minutes": time_window,
|
||||
},
|
||||
}
|
||||
|
||||
async def _error_logs_summary(self, client, parameters: dict) -> dict:
|
||||
"""Get error logs summary (Phase 13.1 #77)"""
|
||||
service_name = parameters.get("service_name")
|
||||
if not service_name:
|
||||
return {"error": "Missing 'service_name' parameter"}
|
||||
|
||||
time_window = parameters.get("time_window_minutes", 60)
|
||||
|
||||
summary = await client.get_error_logs_summary(
|
||||
service_name=service_name,
|
||||
time_window_minutes=time_window,
|
||||
)
|
||||
|
||||
return summary
|
||||
|
||||
async def health_check(self) -> bool:
|
||||
"""Check if SignOz is accessible"""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user