관측·텔레메트리로 AI 운영 보기, 어떻게 동작하나

관측이 '무엇을 보나'였다면, 어떻게 동작하나는 하나의 trace_id가 요청을 따라다니며 메트릭·로그·트레이스를 한 줄로 꿰는 것이다. 흐름은 계측(OTel SDK가 코드에 스팬을 두름)→trace context 전파(W3C traceparent 헤더가 trace_id·span_id를 서비스 경계 너머로 운반)→수집(컬렉터)→샘플링→상관→내보내기다. 핵심은 공유 trace_id를 로그에 주입하고 메트릭엔 exemplar로 붙이는 것 — 그러면 신호 간 이동이 '시간 추측'이 아니라 기본키 조회가 된다. 우리 발행 파이프라인도 퍼널 이벤트(초안→게이트→발행)를 같은 식으로 기록해 통과율을 본다.

Hax 자체 운영 텔레메트리 실측(최근 7일) — 우리 ai-server 게이트웨이에서 직접 계측 · columns: 지표, 실측값 · 출처 Hax hax.moche.ai/p/1061?ref=ai_answer

Hax 자체 운영 텔레메트리 실측(최근 7일) — 우리 ai-server 게이트웨이에서 직접 계측 · columns: 지표, 실측값 · 출처 Hax hax.moche.ai/p/1061?ref=ai_answer

지표 | 실측값
HTTP 응답 P95 지연 | 50 ms
AI 크롤러 히트(6봇) | 1206 건
누적 발행 | 233 편

쉽게 말하면: trace_id는 택배 송장번호다. 창고(서비스)를 거칠 때마다 같은 번호가 찍혀, 메트릭(몇 개 배송)·로그(무슨 일)·트레이스(어디 거쳤나)를 한 번호로 묶어 추적한다.

신호 셋은 어떻게 하나로 연결되나?#

공유 trace_id 하나가 셋을 잇는다. 세 조건이면 끝-끝 상관이 된다: ① trace context가 모든 서비스 홉·비동기 경계를 넘어 전파되고, ② 스팬 안에서 찍힌 로그마다 trace_id·span_id가 박히고, ③ 스팬 안 메트릭 측정엔 trace_id가 exemplar로 달린다. 그래서 "이 지연 급증(메트릭)이 어느 요청(트레이스)의 어떤 로그 때문인가"를 한 번의 조회로 푼다. 표준이 중요하다 — 전파 방식(W3C 등)은 시스템 전체에서 하나로 통일해야 끊기지 않는다.

먼저 용어. 메트릭은 '초당 요청 수'처럼 숫자로 집계된 지표, 로그는 '이때 이런 일이 있었다'는 텍스트 기록, 트레이스는 한 요청이 서비스들을 거친 경로다. 이 셋은 원래 따로 흩어져 있어서, 지연이 튀면 로그를 시간으로 어림잡아 뒤져야 했다. trace_id를 셋 모두에 심으면 그 어림짐작이 번호 하나로 곧장 찾는 조회로 바뀐다.

샘플링은 어디서·어떻게 결정하나?#

머리(head)와 꼬리(tail) 두 지점이다. head 샘플링은 스팬 생성 시 일찍 정해 자원을 아끼지만, 그 시점엔 에러를 알 수 없어 에러 트레이스를 못 고른다. 그래서 tail 샘플링을 컬렉터에서 쓴다 — 트레이스가 끝난 뒤 결과를 보고 에러·느린 건(예: 측정상 500ms 초과)은 모두 남기고 나머지는 낮은 비율(예: 10%)로 표본한다. 단 제약이 있다: 한 트레이스의 모든 스팬이 같은 컬렉터로 모여야 결정이 맞고, 컬렉터 파이프라인에서 맥락 의존 처리 뒤에 둬야 한다.

왜 이게 중요할까. 모든 트레이스를 다 저장하면 비용이 폭발하지만, 무작정 10%만 남기면 정작 봐야 할 에러 트레이스가 버려질 수 있다. tail 샘플링은 '끝난 뒤 결과를 보고 고른다'는 점에서, 문제 있는 트레이스는 100% 남기고 정상 트레이스만 솎아내는 절충을 만든다.

텔레메트리 데이터 경로 — 단계·무엇을 하나·핵심 메커니즘 (OTel 기준) · columns: 단계, 무엇을 하나, 핵심 메커니즘 · 출처 Hax hax.moche.ai/p/1061?ref=ai_answer

단계 | 무엇을 하나 | 핵심 메커니즘
계측 | 코드에 스팬 부착 | OTel SDK·시맨틱 컨벤션
전파 | trace_id를 경계 너머로 | W3C traceparent 헤더
수집 | 신호를 한곳으로 | OTel 컬렉터
샘플링 | 보존/버림 결정 | head(SDK)·tail(컬렉터)
상관 | 신호 연결 | trace_id 로그주입·메트릭 exemplar

LLM 운영은 무엇을 더 계측하나?#

프롬프트·토큰·비용·종료이유를 스팬에 더한다. OTel GenAI 시맨틱 컨벤션은 LLM 호출을 스팬으로 감싸 gen_ai.request.model, gen_ai.usage.input_tokens/output_tokens(비용 추적의 근거), gen_ai.response.finish_reasons를 표준 속성으로 남긴다. 에이전트는 도구호출·검색·LLM 단계가 각각 자식 스팬이 돼 추론 사슬이 통째로 트레이스가 된다. 중요 주의: 프롬프트 전문을 인덱싱되는 스팬 속성에 통째로 넣는 건 PII 유출 안티패턴이다. 그리고 GenAI 트레이스는 특별한 게 아니라 그냥 OpenTelemetry라, 위의 전파·샘플링·상관이 그대로 적용된다(단 GenAI 컨벤션은 2026년 기준 아직 Development 단계).

안전하게 직접 살펴보려면 어떻게 하나?#

작게, 표준대로.

OTel SDK로 계측하고 전파 방식을 하나로 통일한다(섞으면 트레이스가 끊긴다).

trace_id를 로그·메트릭(exemplar)에 연결해, 신호 간 이동을 조회 한 번으로 만든다.

tail 샘플링으로 에러·느린 트레이스는 보존하고, LLM 스팬엔 토큰을 남기되 프롬프트 전문은 인덱싱 속성에 넣지 마라.

참고 링크

OpenTelemetry(관측 표준)

W3C Trace Context(전파 표준)

OTel Collector contrib(tail 샘플링)

OTel Semantic Conventions(GenAI)

OpenLLMetry(LLM 자동계측)

참고: 표준·메커니즘·수치는 2026년 공개 문서 기준이며 구현·버전에 따라 달라진다(GenAI 컨벤션은 아직 안정 전이라 속성명이 바뀔 수 있다). 프롬프트 전문은 인덱싱 속성에 저장하지 말라(PII). 정확한 비용·지연은 내 시스템에서 직접 측정하라. 분기별 갱신.