관측·텔레메트리로 AI 운영 보기, 어떻게 동작하나
요약: 관측이 '무엇을 보나'였다면, 어떻게 동작하나는 하나의 trace_id가 요청을 따라다니며 메트릭·로그·트레이스를 한 줄로 꿰는 것이다. 흐름은 계측(OTel SDK가 코드에 스팬을 두름)→trace context 전파(W3C traceparent 헤더가 trace_id·span_id를 서비스 경계 너머로 운반)→수집(컬렉터)→샘플링→상관→내보내기다. 핵심은 공유 trace_id를 로그에 주입하고 메트릭엔 exemplar로 붙이는 것 — 그러면 신호 간 이동이 '시간 추측'이 아니라 기본키 조회가 된다. 우리 발행 파이프라인도 퍼널 이벤트(초안→게이트→발행)를 같은 식으로 기록해 통과율을 본다.
관측이 '무엇을 보나'였다면, 어떻게 동작하나는 하나의 trace_id가 요청을 따라다니며 메트릭·로그·트레이스를 한 줄로 꿰는 것이다. 흐름은 계측(OTel SDK가 코드에 스팬을 두름)→trace context 전파(W3C traceparent 헤더가 trace_id·span_id를 서비스 경계 너머로 운반)→수집(컬렉터)→샘플링→상관→내보내기다. 핵심은 공유 trace_id를 로그에 주입하고 메트릭엔 exemplar로 붙이는 것 — 그러면 신호 간 이동이 '시간 추측'이 아니라 기본키 조회가 된다. 우리 발행 파이프라인도 퍼널 이벤트(초안→게이트→발행)를 같은 식으로 기록해 통과율을 본다.
| 지표 | 실측값 |
|---|---|
| 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 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). 정확한 비용·지연은 내 시스템에서 직접 측정하라. 분기별 갱신.
Responses
No responses yet. Be the first to respond.