fix(mcp): enrich host log evidence params
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
CD Pipeline / tests (push) Successful in 2m29s
CD Pipeline / build-and-deploy (push) Successful in 4m15s
CD Pipeline / post-deploy-checks (push) Successful in 1m41s

This commit is contained in:
Your Name
2026-05-18 12:23:39 +08:00
parent 0e7fe211de
commit 5cb10a6d2d
4 changed files with 87 additions and 9 deletions

View File

@@ -619,17 +619,30 @@ def _build_tool_params(incident: "Incident") -> dict[str, Any]:
or target
or pod_name
)
container_name = (
labels.get("container_name")
or labels.get("container")
or labels.get("name")
or service_name
)
log_severity = labels.get("log_severity") or labels.get("severity", "")
if not log_severity and any(k in alertname.lower() for k in ("error", "fatal", "critical")):
log_severity = "ERROR,FATAL,CRITICAL"
return {
"namespace": namespace,
"pod_name": pod_name,
"deployment": labels.get("deployment", ""),
"host": host,
"container": labels.get("container", labels.get("name", "")),
"container_name": container_name,
"filter_name": labels.get("filter_name") or container_name,
"target": target,
"service": labels.get("unit") or labels.get("service") or service_name,
"service_name": service_name,
"alertname": alertname,
"search_text": alertname,
"severity": labels.get("severity", ""),
"severity": log_severity,
"time_window_minutes": 30,
"limit": 100,
# P0.4 fix 2026-04-24 ogt + Claude Sonnet 4.6: Prometheus tool 需要 query 欄位

View File

@@ -433,8 +433,8 @@ class SignOzClient:
"""
從 SignOz/ClickHouse 查詢日誌 (Phase 13.1 #77)
SignOz 日誌儲存在 signoz_logs.distributed_logs 表
Schema: timestamp, severity_text, body, resources, attributes
SignOz v0.8+ 日誌儲存在 signoz_logs.distributed_logs_v2
Schema: timestamp, severity_text, body, resources_string, attributes_string
Args:
service_name: 服務名稱 (過濾 resources.service.name)
@@ -458,7 +458,8 @@ class SignOzClient:
if service_name:
# SignOz 儲存 service.name 在 resources 欄位
conditions.append(f"resources['service.name'] = '{service_name}'")
safe_service = service_name.replace("'", "''")
conditions.append(f"resources_string['service.name'] = '{safe_service}'")
if severity:
# 支援多個級別 (如 'ERROR,WARN')
@@ -478,11 +479,11 @@ class SignOzClient:
timestamp,
severity_text,
body,
resources,
attributes,
resources_string AS resources,
attributes_string AS attributes,
trace_id,
span_id
FROM signoz_logs.distributed_logs
FROM signoz_logs.distributed_logs_v2
WHERE {where_clause}
ORDER BY timestamp DESC
LIMIT {limit}
@@ -532,11 +533,11 @@ class SignOzClient:
severity_text,
count() as count,
any(body) as sample_message
FROM signoz_logs.distributed_logs
FROM signoz_logs.distributed_logs_v2
WHERE
timestamp >= {start_ns}
AND timestamp <= {end_ns}
AND resources['service.name'] = '{service_name}'
AND resources_string['service.name'] = '{service_name.replace("'", "''")}'
AND severity_text IN ('ERROR', 'FATAL', 'CRITICAL')
GROUP BY severity_text
ORDER BY count DESC

View File

@@ -166,6 +166,9 @@ def test_build_tool_params_uses_host_alias_and_service_from_affected_service() -
assert params["host"] == "192.168.0.188"
assert params["target"] == "ollama"
assert params["service_name"] == "ollama"
assert params["container_name"] == "ollama"
assert params["filter_name"] == "ollama"
assert params["severity"] == "ERROR,FATAL,CRITICAL"
assert params["search_text"] == "HostErrorLogFlood"
assert params["time_window_minutes"] == 30

View File

@@ -0,0 +1,61 @@
from __future__ import annotations
import pytest
from src.services.signoz_client import SignOzClient
@pytest.mark.asyncio
async def test_get_logs_uses_live_signoz_v2_table(monkeypatch) -> None:
client = SignOzClient()
queries: list[str] = []
async def fake_query(query: str) -> list[dict]:
queries.append(query)
return [
{
"timestamp": 1,
"severity_text": "ERROR",
"body": "boom",
"resources": {"service.name": "ollama"},
"attributes": {"container.name": "ollama"},
"trace_id": "trace-1",
"span_id": "span-1",
}
]
monkeypatch.setattr(client, "_query_clickhouse", fake_query)
logs = await client.get_logs(
service_name="ollama",
severity="ERROR",
search_text="HostErrorLogFlood",
time_window_minutes=5,
limit=3,
)
assert logs[0]["service"] == "ollama"
assert "FROM signoz_logs.distributed_logs_v2" in queries[0]
assert "resources_string['service.name'] = 'ollama'" in queries[0]
assert "attributes_string AS attributes" in queries[0]
@pytest.mark.asyncio
async def test_error_logs_summary_uses_live_signoz_v2_table(monkeypatch) -> None:
client = SignOzClient()
queries: list[str] = []
async def fake_query(query: str) -> list[dict]:
queries.append(query)
return [{"severity_text": "ERROR", "count": 2, "sample_message": "boom"}]
monkeypatch.setattr(client, "_query_clickhouse", fake_query)
summary = await client.get_error_logs_summary(
service_name="ollama",
time_window_minutes=5,
)
assert summary["total_errors"] == 2
assert "FROM signoz_logs.distributed_logs_v2" in queries[0]
assert "resources_string['service.name'] = 'ollama'" in queries[0]