프론트엔드에서 500 오류가 발생했다. 스택 트레이스는 React 컴포넌트를 가리킨다. 실제 문제는 세 개의 서비스 뒤에 있고, 누수하는 백그라운드 작업에 의해 고갈된 데이터베이스 커넥션 풀에 있다.

트레이스 폭포를 클릭해가며 타임스탬프를 연관 짓고 커밋 기록을 읽을 수도 있다. 아니면 Sentry의 Seer에게 맡길 수도 있다. Seer는 트레이스, 오류, 코드를 읽어 무엇이 고장 났는지 알려주는 LLM 기반 디버깅 에이전트다.

Seer는 이것을 잘한다. 초능력자는 아니다. 이 두 문장 사이의 간극이 이 글의 주제다.

Statistical debugging의 실제 의미

Statistical debugging은 많은 실행에 걸친 패턴을 사용해 버그를 정확히 찾는다. 기존 디버거는 한 번의 실행을 보여준다. Statistical 접근법은 분포를 본다: 어떤 함수가 함께 실패하는지, 어떤 트레이스가 오류와 연관되는지, 어떤 커밋이 크래시 급증에 앞섰는지.

Sentry는 수년간 통계적 부분을 해왔다. Seer는 그 데이터 위에 인과관계를 추론하는 LLM을 추가한다. 통계를 대체하지 않는다. 해석한다.

Seer는 허깨비 근본 원인을 아무것도 없는 곳에서 환상하지 않는다. 당신이 볼 트레이스와 스택 트레이스를 똑같이 본다. 하지만 수천 개의 span을 몇 초 만에 읽고 codebase와 연관 짓는다.

Seer가 span의 바다에 빠지지 않고 트레이스를 읽는 방법

분산 트레이스는 수천 개의 span을 포함할 수 있다. 이 모든 것을 LLM 컨텍스트 윈도우에 집어넣으면 혼란의 레시피다. 모델은 관련 없는 세부 사항에 집착하고 신호를 놓친다.

Sentry는 이를 압축된 트레이스 트리를 구축함으로써 해결한다. 모든 span 대신, Seer는 transaction의 계층 구조를 본다. transaction은 span을 의미 있는 단위로 묶는 service boundaries다. 트리는 어떤 transaction이 어떤 것을 호출했는지, 각각 얼마나 걸렸는지, 내부에서 어떤 오류가 발생했는지 보여준다.

원시 트레이스가 개념적으로 어떻게 생겼는지 보자:

GET /api/checkout
├── POST /payment-service/process
│   ├── SELECT * FROM orders
│   └── UPDATE inventory
├── GET /user-service/profile
│   └── SELECT * FROM users WHERE id = ?
└── POST /notification-service/email
    └── SMTP send

Seer는 타이밍과 오류 상태가 주석된 이 트리를 받는다. 체크아웃 요청이 세 개의 다운스트림 서비스를 호출했다는 것을 본다. 데이터베이스 쿼리 하나하나는 요청하지 않는 한 보이지 않는다.

핵심 단어는 “요청하지 않는 한”이다. Seer에는 도구가 있다. 트리가 결제 서비스에 문제가 있다고 암시한다면, 해당 transaction 내부의 전체 span, ID로 연결된 오류 이벤트, CPU 프로파일을 가져올 수 있다. 다음에 무엇을 볼지 스스로 결정한다.

이 에이전틱 접근법이 “이 트레이스를 ChatGPT에 붙여넣기”와 Seer가 실제로 하는 것 사이의 차이점이다. 챗봇은 한 번의 기회를 가진다. Seer는 루프를 가진다: 관찰, 추론, 더 많은 데이터 가져오기, 다시 추론.

Seer가 해결하도록 설계된 크로스 서비스 문제

트레이스 이전에는, Seer(당시 Autofix라 불렸다)는 스택 트레이스와 breadcrumb에 의존했다. 이것은 거대한 codebase에서는 작동했다. 분산 시스템에서는 실패했다.

프론트엔드 500 오류를 생각해 보자. 스택 트레이스는 fetch 호출을 가리킨다. 트레이스 없이는 Seer가 프론트엔드가 고장 났다고 결론 내릴 것이다. 트레이스가 있으면, 프론트엔드가 API 게이트웨이를 호출했고, 그것이 인증 서비스를 호출했고, 인증 서비스가 인증서가 교체되어 토큰 검증 오류를 던졌다는 것을 본다.

Sentry 자체 팀도 내부적으로 이 문제를 겪었다. Sentry 백엔드와 Seer 마이크로서비스 사이의 인증 문제가 수일간 지속되었다. Seer는 트레이스 트리와 두 저장소에 대한 접근 권한을 받고, 근본 원인을 식별하고 두 서비스에 풀 리퀘스트를 열었다.

그것이 약속이다. 문제는 설정이다.

Seer가 도움이 되기 전에 필요한 것

Seer가 잘 작동하려면 세 가지가 필요하다:

1. 연결된 트레이스.

서비스들이 분산 트레이싱 없이 다른 Sentry 프로젝트를 사용한다면, Seer는 고립된 오류를 볼 뿐이고 트레이스 트리는 보이지 않는다. 각 서비스에 Sentry SDK와 트레이스 헤더 전파가 필요하다.

파이썬에서는:

import sentry_sdk

sentry_sdk.init(
    dsn="https://your-dsn.ingest.sentry.io/project-id",
    traces_sample_rate=0.1,  # Adjust for your volume
)

크로스 서비스 전파를 위해, SDK는 지원되는 HTTP 클라이언트에서 sentry-tracebaggage 헤더를 자동으로 읽고 쓴다. 직접 클라이언트를 만든다면 헤더를 수동으로 첨부하라:

from sentry_sdk import continue_trace

headers = {}
continue_trace(headers).apply_to_request(headers)
response = my_custom_http_client.get(
    "http:// downstream-service/api",
    headers=headers,
)

이것이 없으면 Seer는 프론트엔드와 백엔드 오류를 관련 없는 사건으로 본다. 트레이스 트리는 형성되지 않는다.

2. 연결된 코드.

Seer는 트레이스를 구현과 연관 짓기 위해 codebase를 검색한다. 이것은 GitHub 통합과 저장소를 Sentry 프로젝트에 매핑하는 것을 필요로 한다. Seer는 zip 파일이나 로컬 경로에서 코드를 읽을 수 없다.

3. 충분한 신호.

자동 계측된 HTTP span만 있는 트레이스는 Seer에게 서비스 A가 서비스 B를 호출했다는 사실만 알려준다. 그 사이에서 어떤 비즈니스 로직이 일어났는지는 알려주지 않는다. 커스텀 span이 중요하다.

from sentry_sdk import start_span

def process_payment(order_id):
    with start_span(op="payment.process", description="Validate and charge"):
        validate_order(order_id)
        charge_customer(order_id)

이것이 없으면, Seer는 HTTP 요청과 데이터베이스 쿼리 사이의 블랙박스를 본다.

아무도 마케팅 카피에 넣지 않는 트레이드오프

Seer에는 실제 한계가 있으며, Sentry는 이에 대해 상당히 정직하다.

정확도는 높지만 100%는 아니다.

Sentry는 근본 원인 식별률을 94.5%로 보고한다. 즉 대략 20건 중 1건이 오진된다. 고심각도 사고의 경우, 수정을 배포하기 전에 인간이 Seer의 결론을 검증해야 한다.

실행당 비용이 든다.

Seer 실행은 근본 원인 분석당 약 1달러에 월간 구독료가 추가된다. 자동화된 스캔은 건당 0.003달러로 더 저렴하다. 매일 수십 건의 이슈를 처리하는 팀에게는 이것이 누적된다. 자동화 임계값을 신중하게 설정하라.

볼 수 없는 것은 고칠 수 없다.

트레이스가 1%로 샘플링되고 버그가 나머지 99%에서만 나타난다면, Seer는 찾지 못할 것이다. 근본 원인이 Sentry로 트레이스를 보내지 않는 서드파티 서비스에 있다면, Seer는 벽에 부딪힐 것이다. 이슈가 오류를 전혀 던지지 않는 논리적 버그라면, Seer는 절대 트리거되지 않을 것이다.

LLM은 여전히 일부 추론에서 약하다.

마이크로소프트 연구는 대부분의 개발자가 의심하는 것을 확인했다: AI 에이전트는 문제를 로컬라이즈하는 데 탁월하지만, 원인이 증상으로부터 멀리 떨어져 있을 때 근본 원인 분석에 어려움을 겪는다. 시간에 걸친 인과관계, 특히 race condition나 상태 손상의 경우는 여전히 어렵다.

Seer가 빛나는 때와 건너뛰어야 할 때

Seer를 시도할 가치가 있는 경우:

  • 여러 서비스에 걸쳐 연결된 트레이스를 가진 분산 시스템이 있는 경우
  • 이슈가 Sentry가 포착한 명확한 오류 이벤트를 포함하는 경우
  • 근본 원인이 자신의 코드에 있을 가능성이 높고 서드파티 의존성에 있지 않은 경우
  • 수동 조사가 지루할 만큼 충분한 트레이스 볼륨이 있는 경우

건너뛰어야 할 경우:

  • 트레이스가 서비스 간에 연결되지 않은 경우
  • 이슈가 간헐적이고 트레이스에서 드물게 포착되는 경우
  • 활성 사고에 대해 1분 미만의 해상도가 필요한 경우(Seer는 실행에 몇 분이 걸린다)
  • 근본 원인이 코드가 아닌 인프라일 가능성이 거의 확실한 경우

실제로 시도하는 방법

유료 Sentry 플랜을 사용 중이라면, Seer는 14일 무료 평가판으로 사용 가능하다.

  1. Sentry 조직 설정에서 GitHub 연결
  2. Seer 설정에서 저장소를 Sentry 프로젝트에 매핑
  3. SDK에서 traces_sample_rate가 설정된 트레이싱이 활성화되어 있는지 확인
  4. 아무 이슈나 열고 Find Root Cause 클릭

자동 실행의 경우 중단점을 설정하라. 대부분의 팀은 Stop after Root Cause로 시작한다. 정확도를 신뢰하게 되면, 해결책 제안이나 풀 리퀘스트 초안 작성을 허용할 수 있다.

Cursor나 Claude Code를 사용한다면, IDE 채팅에서 Sentry의 MCP server를 통해 직접 Seer를 호출할 수 있다.

정직한 결론

Seer는 압축된 트레이스 트리를 구축하고, 요청 시 상세 데이터를 가져오고, codebase에 걸쳐 추론함으로써 트레이스에서 근본 원인을 찾을 수 있다. 연결되고 잘 계측된 분산 시스템의 경우, 이는 진정으로 유용하다. Sentry 자체 엔지니어들은 크로스 서비스 이슈에서 며칠의 디버깅 시간을 절약했다.

자신의 시스템을 이해하는 것의 대체재는 아니다. 트레이스와 코드를 읽을 수 있는 매우 빠르고, 매우 많이 읽은 인턴이지만, 여전히 가끔 잘못된 서비스를 탓하는 인턴이다. 조사를 가속화하는 데 사용하라. 제거하는 데 사용하지 마라.

트레이스가 깨끗하고 연결되어 있으며 유용한 span으로 가득 차 있다면, Seer는 아마 당신을 인상시킬 것이다. 그렇지 않다면, 먼저 트레이스를 고쳐라. 계측하지 않은 것을 디버깅할 수 있는 LLM은 없다.


FAQ

Seer가 self-hosted Sentry와 작동하는가? 아니다. Seer는 sentry.io가 필요한 클라우드 서비스다. LLM 에이전트를 실행하고 텔레메트리에 접근하려면 Sentry 자체 인프라에 의존한다. Self-hosted 인스턴스는 Seer에 접근할 수 없다.

Seer가 파이썬과 자바스크립트 이외의 언어 트레이스를 분석할 수 있는가? 예. Seer는 Sentry의 트레이스 데이터를 읽지, 언어별 원시 텔레메트리를 읽지 않는다. Sentry SDK로 계측되어 트레이스를 생성하는 모든 서비스는 Seer로 공급될 수 있다. 코드 분석 단계는 GitHub 통합이 필요하며, 이는 모든 언어에서 작동한다.

Seer가 근본 원인을 틀리게 맞추면 어떻게 되는가? 분석 중에 피드백을 제공할 수 있고, Seer는 이를 반영할 것이다. 최종 출력은 코드 변경이 적용되거나 PR이 열리기 전에 항상 인간의 승인이 필요하다. 명시적으로 설정하지 않는 한 아무것도 자동으로 배포되지 않는다.

이것이 스택 트레이스를 Claude나 ChatGPT에 붙여넣는 것과 무엇이 다른가? 챗봇은 당신이 붙여넣은 것만 가진 단일 컨텍스트 윈도우를 가진다. Seer는 전체 트레이스 트리, 연결된 오류, CPU 프로파일, codebase에 접근할 수 있는 에이전틱 루프를 가진다. 추론하면서 더 많은 데이터를 가져올 수 있고, 실제 코드를 읽기 때문에 시스템의 구조를 안다.