Claude Code가 OpenTelemetry를 내보내기 시작했습니다: Grafana에서 어떤 모델에 얼마를 소비하는지
요약
Claude Code가 OpenTelemetry 익스포터를 배포하여 사용량 추적 기능을 강화했습니다. 이를 통해 API 요청별로 비용과 토큰 사용량을 모델, 사용자, 세션 등 다양한 기준으로 상세하게 모니터링할 수 있습니다. 이 가이드는 Docker Compose를 이용해 전체 파이프라인을 구축하고 Grafana에서 시각화하는 방법을 안내합니다.
핵심 포인트
- Claude Code가 OpenTelemetry 익스포터를 지원하여 사용량 추적 가능
- 비용 및 토큰 사용량을 모델, 서브 에이전트별로 상세하게 분리 분석 가능
- Prometheus와 Grafana를 활용해 통합 모니터링 대시보드 구축 방법 제시
- 도서: LLM Observability Pocket Guide
- 저자 소개: Thinking in Go (2권 시리즈) — Complete Guide to Go Programming + Hexagonal Architecture in Go
- 프로젝트: Hermes IDE | GitHub — Claude Code 및 기타 AI 코딩 도구와 함께 배포하는 개발자를 위한 IDE
- 저자: xgabriel.com | GitHub
팀의 Claude Code 사용 비용이 청구서에 하나의 숫자로 기록됩니다. 그러고 나서 누군가 당연한 후속 질문을 던집니다. 지난달 급증세를 어떤 팀이 주도했는가? 비싼 모델 때문인가, 아니면 저렴한 모델 때문인가? 서브 에이전트들이 조용히 예산의 절반을 소진하고 있는 것은 아닌가? 아무도 대답할 수 없습니다. 왜냐하면 그 답을 줄 데이터 자체가 활성화되지 않았기 때문입니다.
Claude Code는 OpenTelemetry 익스포터를 배포합니다. OpenTelemetry를 내보내기는 환경 변수 CLAUDE_CODE_ENABLE_TELEMETRY=1을 설정해야만 활성화되는데, 이는 모니터링 문서에 명시되어 있습니다. 몇몇 추가 문서는 데이터가 어디로 가는지 알려줍니다. 일단 활성화되면 모든 API 요청은 비용 카운터를 증가시키고 토큰 카운터를 증가시키며, 각각 모델, 사용자, 세션, 그리고 해당 호출을 수행한 Claude Code의 부분별로 태그가 지정됩니다.
이 워크스루는 전체 파이프라인을 노트북에서 실행합니다: Claude Code를 OpenTelemetry Collector에 넣고, 이를 Prometheus가 스크랩하고, Grafana가 그리는 모든 것을 하나의 Docker Compose 파일에서 처리합니다. 그런 다음 서론의 질문 각각에 대해 패널을 하나씩 만듭니다.
Claude Code가 내보내는 것 (그리고 숨기는 것)
스펜드 대시보드를 위해 두 가지 신호가 중요합니다. 메트릭은 메트릭 익스포터(metrics exporter)를 통해 전송되고, 이벤트는 로그 익스포터(logs exporter)를 통해 전송됩니다. 문서에 따르면, 메트릭은 다음과 같습니다:
claude_code.cost.usage(USD): API 요청마다 증가하며, 활성 스킬(skill), 플러그인 또는 서브 에이전트에 대한model,query_source(main,subagent또는auxiliary),effort, 및 귀속 정보를 포함합니다.claude_code.token.usage(tokens):type:input,output,cacheRead,cacheCreation별로 분할됩니다.claude_code.session.count,claude_code.lines_of_code.count,claude_code.commit.count,claude_code.pull_request.count,claude_code.active_time.total.claude_code.code_edit_tool.decision: Edit, Write 및 NotebookEdit에서 수락(accept) 및 거부(reject) 결정을 계산하며, 파일의language를 포함합니다.
이벤트에는 user_prompt, api_request (cost_usd, duration_ms 및 호출당 토큰 카운트가 포함됨), api_error, tool_result 및 tool_decision이 포함됩니다.
모든 메트릭과 이벤트는 무작위 설치 식별자인 session.id와 user.id를 가집니다. Claude 계정으로 로그인하면, 또한 organization.id, user.account_uuid 및 user.email도 얻게 되며, 문서에 따르면 이메일은 구성하는 엔드포인트로만 전송되고 Anthropic에는 절대 전송되지 않습니다.
기본값은 비공개(private)에 가깝습니다. 사용자가 프롬프트 텍스트는 수집되지 않고 길이만 수집되며, OTEL_LOG_USER_PROMPTS=1로 설정하지 않는 한 그렇습니다. Bash 명령어와 MCP 도구 인수는 OTEL_LOG_TOOL_DETAILS=1로 설정하지 않으면 제외됩니다. 문서에는 또한 원본 파일 내용과 코드 스니펫이 메트릭이나 이벤트의 일부가 아니라고 명시되어 있습니다. 비용 대시보드를 위해서는 이 모든 플래그를 비활성화하십시오. 그것들은 필요하지 않습니다.
스택: 네 개의 작은 파일
디렉토리를 만들고 그 안에 네 개의 파일을 넣으십시오. Collector는 Claude Code로부터 OTLP를 수신하고 포트 8889에서 Prometheus 형식으로 메트릭을 재노출합니다. Prometheus가 이를 스크랩(scrape)합니다. Grafana가 Prometheus를 읽습니다.

Claude Code가 OTLP를 Collector로 전송하고, Prometheus가 이를 스크랩하며, Grafana에서 시각화합니다.
Collector, Prometheus 및 Grafana의 현재 릴리스에 이미지 태그를 고정한 docker-compose.yml 파일:
services:
otel-collector:
image: otel/opentelemetry-collector-contrib:0.162.0
...
Prometheus exporter로 메트릭을 전송하는 otel-collector.yaml. 이벤트는 로그 스토어를 실행하지 않아도 컨테이너 로그에서 확인할 수 있도록 debug exporter로 전송됩니다:
receivers:
otlp:
protocols:
...
prometheus.yml:
global:
scrape_interval: 15s
...
클릭을 건너뛸 수 있도록 provisioned data source인 grafana/prometheus.yaml:
apiVersion: 1
datasources:
- name: Prometheus
...
그런 다음 docker compose up -d를 실행합니다. Grafana는 포트 3000에 있으며 (사용자명 admin, 비밀번호는 Compose 파일에서 확인 가능).
Claude Code에 연결하기
Claude Code를 시작하는 셸에서:
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
...
이 세 줄은 따로 설명할 가치가 있습니다.
시간성(temporality) 라인입니다. Claude Code의 기본값은 delta이며, 백엔드가 이를 예상하는 경우 cumulative로 전환해야 한다고 문서에 나와 있습니다. Prometheus 카운터는 누적형(cumulative)이고, Collector의 Prometheus exporter README에는 delta 합계 처리 방식이 문서화되어 있지 않으므로, 소스에서 cumulative를 요청하면 이 질문 자체가 사라집니다.
내보내기 간격입니다. 기본값은 60,000ms입니다. 문서는 디버깅 중에는 더 짧은 간격을 사용할 것을 제안합니다. 10초면 첫 수치가 빠르게 표시됩니다. 문제가 해결되면 기본값으로 되돌리세요.
리소스 속성입니다. OTEL_RESOURCE_ATTRIBUTES 키는 기본적으로 모든 메트릭 데이터 포인트에 레이블로 포함되며, 따라서 team.id=platform을 사용하면 팀 차원(dimension)을 무료로 얻을 수 있습니다. 값에는 공백이 포함될 수 없습니다.
프롬프트 몇 개를 실행한 다음 Collector가 어떤 것을 노출하는지 확인하세요:
curl -s localhost:8889/metrics | grep '^claude_code'
추측하기보다는 이 출력에서 메트릭 이름을 읽으세요. exporter는 점(.)을 밑줄(_)로 바꾸고 카운터에 단위와 _total을 추가하므로, 비용 카운터는 claude_code_cost_usage_USD_total로, 토큰은 claude_code_token_usage_tokens_total로 표시됩니다. 이들은 Anthropic의 GitHub 조직 내 ROI 측정 가이드에서 쿼리하는 정확한 이름입니다. 레이블도 같은 규칙을 따릅니다: user.email은 user_email이 되고, team.id는 team_id가 됩니다. 아무것도 표시되지 않으면 문서는 claude --debug-file <경로>를 사용하고 [3P telemetry] 오류를 검색할 것을 권장합니다.
이를 한 노트북이 아닌 팀 전체에 배포하려면, 동일한 변수를 Claude Code의 관리 설정 파일의 env 블록에 넣으세요. 문서는 리포지토리의 .claude/settings.json으로는 텔레메트리를 활성화하거나 리디렉션할 수 없다고 명시하므로, 잘못된 리포 config가 데이터를 다른 곳으로 빼돌릴 수 없습니다.
세 개의 패널
대시보드를 만드세요. 각 패널에 대해 Bar gauge 시각화를 선택하고, 쿼리 유형을 Instant로 설정하며, 대시보드의 시간 창과 동일한 Grafana의 $__range 변수를 사용하세요. 시간 선택기를 30일로 변경하면 모든 패널이 따라갑니다.
누가 소비하는지. 선택된 기간 동안 사용자당 예상 USD:
sum by (user_email) (
increase(claude_code_cost_usage_USD_total[$__range])
)
개발자가 OAuth 대신 API 키로 인증하는 경우 그룹화할 이메일 주소가 없으므로 (자세한 내용은 아래 참조), user_email을 team_id로 변경하면 패널이 팀별 지출액으로 표시됩니다.
어떤 모델인가. 카운터는 같고 레이블만 다릅니다:
sum by (model) (
increase(claude_code_cost_usage_USD_total[$__range])
)
이것은 대화를 시작하는 패널입니다. 특정 모델이 지배적이라면, 다음 질문은 수행되는 작업에 그 모델이 필요한지 여부입니다.
어떤 종류의 작업인가. query_source는 주요 대화와 서브 에이전트 및 보조 요청을 분리합니다:
sum by (query_source) (
increase(claude_code_cost_usage_USD_total[$__range])
)
더 세밀하게 분류하려면 대신 agent_name 또는 skill_name으로 그룹화하세요. 문서에 따르면, OTEL_LOG_TOOL_DETAILS=1이 설정되지 않은 경우 사용자 정의 에이전트 이름은 custom으로, 타사 플러그인 이름은 third-party로 처리되므로 해당 버킷을 예상해야 합니다. 비용 및 토큰 카운터의 경우 이 플래그는 Claude Code v2.1.273 이상에서 필요하며, 이전 버전에서는 설정되어 있어도 여전히 마스킹됩니다.
통계 패널에 유용한 또 다른 쿼리는 프롬프트 캐시에서 제공된 입력 측 토큰의 비율입니다. 문서에 따르면 input 유형은 캐시 읽기 및 쓰기를 제외하므로, 분모는 세 가지를 모두 더해야 합니다:
sum(rate(
claude_code_token_usage_tokens_total{type="cacheRead"}[1h]
))
...
만약 그 비율이 급격히 떨어진다면, 캐싱되는 내용에 무언가 변화가 생겼다는 뜻이며, 토큰 패널은 언제 시작되었는지 알려줍니다.
다음 사항을 유의하며 수치를 읽으세요
추정치입니다. 문서에서 직접 언급했듯이: 비용 측정 항목은 근사치이며, 공식 청구 데이터는 API 제공업체(Claude Console, Amazon Bedrock 또는 Google Cloud)에서 나옵니다. 좌석 기반 플랜을 사용하는 경우, USD 수치를 송장 금액이 아닌 상대적 소비량으로 간주하세요.
게이트웨이 설정에 의존하기 전에 업그레이드하세요. Claude Code v2.1.214 이전에는 ANTHROPIC_BASE_URL 뒤의 프록시를 통해 여러 프레임에 걸쳐 사용량을 보고하는 스트림이 추가 프레임당 대략 한 번의 요청만큼 비용과 토큰 카운터를 부풀렸습니다. 문서 참조.API 키와 클라우드 제공업체는 신원을 담지 않습니다. Bedrock, Google Cloud 또는 Microsoft Foundry와 같은 직접 API 키를 사용하면 user.id(임의 설치 식별자)와 session.id만 채워집니다. 관리 설정이나 실행 래퍼에서 사용자별로 OTEL_RESOURCE_ATTRIBUTES를 통해 신원을 추가해야 합니다.세션 ID는 카디널리티 비용입니다. 기본적으로 모든 시리즈에 session.id가 포함되어 있어 드릴다운을 돕지만 장기 스토리지 공간을 불필요하게 만듭니다. OTEL_METRICS_INCLUDE_SESSION_ID=false를 설정하면 이를 제거할 수 있습니다.짧은 세션은 과소 계산될 수 있습니다. 각 세션은 새로운 시리즈를 시작하며, increase()는 Prometheus가 실제로 스크래핑한 샘플을 기반으로 작동하므로, 시리즈의 첫 번째 스크래핑 전에 이루어진 증가는 누락될 수 있습니다. (prometheus-users 목록에서 설명됨). 짧은 내보내기 간격이 이 격차를 좁힐 수 있습니다. Prometheus에는 또한 created-timestamp-zero-ingestion이라는 기능 플래그가 있어 도움이 될 수 있습니다.데스크톱 세션은 다른 서비스 이름을 사용합니다. Claude Desktop 앱의 Code 탭에서 시작된 로컬 세션은 service.name을 claude-code-desktop으로 보고하며, claude-code가 아닙니다. 필터링할 때 둘 다 추가해야 합니다.## 이 데이터가 알려줄 수 없는 것
패널들은 소비된 비용, 토큰 수, 그리고 승인된 수정 사항의 개수를 보여줍니다. 하지만 이 수치들이 작업의 품질이 좋았는지 여부는 알려주지 않습니다. '승인된 수정 사항(accepted edit)'이란 변경 내용이 검토를 통과했는지 아니면 다음 날 아침에 되돌려졌는지를 나타내는 decision="accept" 데이터 포인트일 뿐입니다. '추가된 라인 수(Lines added)'는 삭제되었어야 할 라인에 대해서는 아무것도 알려주지 못합니다. 개인 정보 보호 기본 설정이 활성화되어 있기 때문에, 어떤 내용이 요청되었는지조차 볼 수 없습니다. 이것은 올바른 기본 설정이며, 동시에 메트릭에서 '왜 이 세션이 비용이 많이 들었는지'라는 질문에 답할 수 없는 이유이기도 합니다.

텔레메트리(Telemetry)는 영수증을 명확하게 보여줍니다. 하지만 작업의 품질은 프레임 밖에 남아 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기