
SigNoz MCP를 사용하여 운영 장애를 자율적으로 조사하는 AI 에이전트를 구축한 방법
요약
SigNoz MCP 서버를 활용하여 운영 장애의 근본 원인을 자율적으로 조사하는 AI 에이전트 'ARIA' 구축 사례를 소개합니다. 단순 조회를 넘어 대시보드와 알림 규칙을 자동으로 생성하는 '쓰기(write)' 기능 구현 과정과 기술적 도전 과제를 다룹니다.
핵심 포인트
- SigNoz MCP 서버를 통한 Observability 데이터 접근 및 제어
- 장애 조사부터 알림 생성까지 수행하는 자율형 에이전트 ARIA 설계
- MCP의 읽기(Read)를 넘어 쓰기(Write) 도구 활용 시의 기술적 난제 해결
- OpenTelemetry 기반의 트레이스, 메트릭, 로그 상관 분석 자동화
새벽 3시, 알람이 울립니다. 앱의 에러율이 40%에 달합니다. 당신은 SigNoz를 열어 깨진 트레이스(traces)를 찾고, 이를 로그(logs)와 상관 분석하며, 가설을 세우고, 런북(runbook)을 작성하고, 다시는 조용히 발생하지 않도록 새로운 알람을 생성합니다. 45분 후, 당신은 다시 잠자리에 듭니다.
저는 그 45분을 없애고 싶었습니다. 더 나은 대시보드를 통해서가 아니라, 스스로 조사를 수행하는 에이전트를 통해서 말입니다.
이것이 제가 Agents of SigNoz 해커톤을 위해 구축한 ARIA (Autonomous Root-cause Investigation Agent, 자율적 근본 원인 조사 에이전트)입니다. 이것이 정확히 어떻게 작동하는지, 과정 중에 무엇이 고장 났는지, 그리고 명확하게 설계되지 않은 용도로 SigNoz의 MCP 서버를 사용하는 것에 대해 무엇을 배웠는지 설명하겠습니다.
설정 (The Setup)
세 가지 프로세스가 함께 실행됩니다:
- target-app — 의도적인 결함 주입(cascade-fail이 발생하고 가짜 DB 타임아웃이 발생하는 두 개의 엔드포인트)이 포함된 FastAPI 서비스
- SigNoz MCP Server — SigNoz Cloud를 가리키며 8002 포트에서 HTTP 프로세스로 실행되는 공식
@signoz/signoz-mcp-server - ARIA — MCP 서버와 통신하고, LLM을 호출하며, 실시간 장애 대시보드를 제공하는 8001 포트의 FastAPI 에이전트
두 서비스 모두 gRPC/TLS를 통해 OpenTelemetry 트레이스(traces), 메트릭(metrics), 로그(logs)를 SigNoz Cloud로 전송합니다. MCP 서버는 REST API를 통해 동일한 SigNoz Cloud 인스턴스와 통신합니다.
아무도 이야기하지 않는 부분: MCP 쓰기 도구 (MCP Write Tools)
제가 찾은 SigNoz MCP 서버의 모든 데모는 누군가가 질문을 던지는 것이었습니다: "에러 로그를 보여줘", "p99 지연 시간(latency)이 얼마야". 그것은 읽기 경로(read path)이며, 아주 잘 작동합니다.
제가 원했던 것은 쓰기(write) 경로였습니다. 근본 원인 분석 (RCA)을 생성한 후, ARIA는 SigNoz에 대시보드와 알림 규칙 (alert rule)을 자동으로 생성해야 했습니다. MCP 서버에는 signoz_create_dashboard, signoz_create_alert, signoz_create_notification_channel과 같은 도구들이 이미 존재했습니다. 하지만 이를 활용할 수 있는 작동하는 예제 코드는 아무도 없었습니다.
signoz_create_alert 도구는 프로젝트 전체에서 가장 어려운 부분이었습니다. v2alpha1 스키마(schema)는 alertType을 문자열 `
그 차이는 제가 예상했던 것보다 더 중요했습니다. 초기 프롬프트(prompt) 버전은 매우 정교했습니다. 사고의 흐름 (chain-of-thought) 지침, 추론 프레임워크 (reasoning frameworks), 출력 형식 가이드 등이 포함되어 있었습니다. 하지만 런북 (runbook) 출력물은 일반적이기만 했습니다. 이를 단지 가공되지 않은 데이터 (raw data)로만 축소하고 "이것을 분석하여 JSON을 반환하라"고 말하자, 런북 단계들이 특정 엔드포인트 (endpoints)와 실제 트레이스 ID (trace IDs)를 참조하기 시작했습니다. 데이터 품질 (Data quality)이 프롬프트 엔지니어링 (prompt engineering)보다 더 중요합니다.
LLM은 다음과 같이 구조화된 JSON을 반환합니다:
{
"severity": "HIGH",
"incident_title": "Cascade failure on /api/orders/cascade",
...
create_dashboard와 create_alert가 true일 때, ARIA는 MCP 쓰기 도구 (write tools)를 호출합니다. 대시보드 (dashboard)와 경고 규칙 (alert rule)은 SigNoz Cloud에 자동으로 나타납니다.
폐쇄형 피드백 루프 (The Closed Feedback Loop)
ARIA가 SigNoz에 생성하는 경고 (alert)는 ARIA 자체의 웹훅 (webhook)을 가리킵니다: http://your-host:8001/webhook/alert.
에러 임계값 (error threshold)이 여전히 초과되어 SigNoz의 alertmanager가 작동하면, 해당 엔드포인트로 신호가 전달됩니다. ARIA는 경고를 수신하고, 또 다른 전체 RCA 사이클을 실행하며, 서비스가 여전히 고장 난 상태라면 심각도 (severity)를 격상합니다:
Cycle 1: 이상 징후 감지 → RCA → 심각도 MEDIUM → signoz_create_alert
[90초 후에도 서비스 여전히 실패 중]
Cycle 2: SigNoz 경고 발생 → /webhook/alert → 재분석 → 심각도 HIGH
...
SigNoz는 단순히 텔레메트리 (telemetry)를 저장하는 것이 아닙니다. 경고 시스템을 통해 ARIA의 동작을 능동적으로 제어하고 있습니다. 이것은 일회성 분석기가 아니라 진정한 제어 루프 (control loop)입니다.
스스로를 관찰하는 ARIA
ARIA는 OpenTelemetry를 사용하여 스스로를 계측(instrument)하며, 자신이 보호하고 있는 것과 동일한 SigNoz Cloud 인스턴스로 데이터를 내보냅니다:
with tracer.start_as_current_span("rca.full_pipeline") as span:
span.set_attribute("rca.service", service)
...
SigNoz Cloud에서 service.name = sentinel-agent로 트레이스(trace)를 필터링하세요. 모든 RCA(근본 원인 분석)가 분산 트레이스(distributed trace)로 표시됩니다. MCP 쿼리 지속 시간, LLM 호출 지연 시간(latency), 대시보드 생성 시간 등이 모두 워터폴(waterfall) 차트에서 확인 가능합니다. 개발 과정에서 이것은 정말 유용했습니다. MCP 호출은 약 200ms 내에 완료되지만 LLM은 7~8초가 걸리는 것을 확인할 수 있었고, 이를 통해 지연 시간 예산(latency budget)이 정확히 어디에서 소모되는지 알 수 있었습니다.
가장 많은 시간을 잡아먹은 버그들
이스케이프된 따옴표가 포함된 API 키.
제 스타트업 스크립트에는 다음과 같이 작성되어 있었습니다:
export SIGNOZ_API_KEY=\"AJDiq+...\"
백슬래시-따옴표가 리터럴 문자로 전달되고 있었습니다. 에이전트는 정상적으로 시작되었고, 읽기 경로(read-path) MCP 도구들도 작동했지만, 모든 쓰기(write) 호출이 401 에러를 반환했습니다. 전송되는 키에 실제 \" 문자가 포함되어 있었던 것입니다. 문제를 발견하기 전까지 엉뚱한 곳을 바라보며 20분을 허비했습니다.
아무것도 반환하지 않는 LLM.
nvidia/nemotron-3-ultra-550b-a55b:free 모델은 속도 제한(rate-limited)에 걸릴 때 가끔 choices: []를 반환합니다. 이는 429 에러가 아니라, 빈 choices 리스트를 가진 유효한 200 응답입니다. 제 원래 코드는 다음과 같았습니다:
raw = response.choices[0].message.content.strip()
이 코드는 조용히 충돌(crash)했습니다. 모니터는 이상 징후를 감지하고 RCA를 시작하지만, IndexError를 만나면 이를 삼켜버리고(swallow) 그냥 넘어가 버립니다. 대시보드에는 아무런 장애도 나타나지 않았고, 로그 메시지도 없었습니다. 아무것도 없었습니다.
해결책:
if not response or not response.choices or response.choices[0].message is None:
logger.warning("LLM이 빈 응답을 반환했습니다 — 속도 제한됨, 다음 사이클에서 재시도합니다")
return {
...
이제 ARIA는 조용히 실패하는 대신 가시적인 LOW 심각도(severity) 인시던트를 생성합니다.
condition.op은 문자열이어야 합니다.
위에서 이미 다뤘지만, 다시 언급할 가치가 있습니다: "3"이지 3이 아닙니다. 두 시간 동안 아무 오류 메시지 없이 400만 반환됩니다.
결과 (Results)
대상 서비스에 30개의 동시 캐스케이드 실패(cascade failures)를 발생시킨 후:
| 지표 (Metric) | 값 (Value) |
|---|---|
| 종단 간 RCA 시간 (End-to-end RCA time) | ~9초 |
| ... |
직접 사용해보기 (Try It Yourself)
git clone https://github.com/kalash33/aria-signoz-agent
cd aria-signoz-agent
cp .env.example .env
...
MCP 쓰기 도구(write tools)가 흥미로운 영역입니다. SigNoz는 대규모로 텔레메트리(telemetry)를 저장, 인덱싱 및 쿼리하는 어려운 부분을 처리합니다. 이 데이터를 발견한 것에 대응하여 SigNoz 리소스를 _생성_할 수 있는 자율 에이전트에 연결하는 곳에서 유용성이 생겨납니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기


