요즘 팀에서 Claude Code, Codex 같은 코딩 에이전트를 도입하는 조직이 늘고 있는데, 막상 “누가 얼마나 쓰고 있는지”, “어느 팀이 토큰을 많이 소비하는지” 같은 질문에는 답하기 어렵습니다. 개발자 개개인의 로컬 터미널에서 돌아가는 도구라, IT 조직 관점에서는 블랙박스에 가깝습니다. 그러다가 최근 Coding Agent Insights - Amazon CloudWatch 문서를 읽게 됐는데, CloudWatch가 OTLP 엔드포인트로 코딩 에이전트의 OpenTelemetry 메트릭을 받아서 전용 대시보드로 보여준다는 내용이었습니다.
호기심이 생겨서 개인 AWS 계정에 Claude Code를 붙여보고, 팀 시나리오를 흉내내기 위해 EC2 위에 여러 사용자 프로파일을 만들어 테스트해봤습니다. 결론부터 말하면, 대시보드 자체는 CloudWatch 콘솔에 기본 제공되는 리소스지만 실제로 값이 채워지려면 에이전트 쪽에서 OTel 리소스 속성을 정확한 형태로 보내야 하고, 여기서 은근히 삽질 포인트가 많았습니다.
이 글에서는 코딩 에이전트가 어떤 텔레메트리를 어떻게 뽑아내는지, CloudWatch의 네이티브 OTLP 엔드포인트가 그걸 어떻게 받아 처리하는지를 먼저 정리하고, 이어서 EC2 기반 개발 환경에서 어떻게 배포했는지, 그리고 무엇을 취사선택했는지를 공유합니다.
범위 명시: 이 글은 Coding Agent Insights의 metrics 경로에 집중합니다. tool 실행 결과 같은 events/logs나 traces는 별도 exporter와 opt-in이 필요하며, 여기서는 다루지 않습니다(뒤의 “시그널 구분” 참고).
(A) 설계 의도와 아키텍처
Claude Code, OpenAI Codex, GitHub Copilot 같은 최신 코딩 에이전트는 이미 내부에 OpenTelemetry SDK를 내장하고 있습니다. 사용자가 프롬프트를 입력할 때마다 세션 단위로 토큰 소비량, 턴당 latency, API 요청 수, 세션과 코드 변경 카운트 같은 것을 방출합니다. 다만 신호(signal)가 하나로 뭉뚱그려지는 게 아니라 metrics / events(logs) / traces로 구분되어 나오는데, Coding Agent Insights 대시보드가 사용하는 것은 이 중 metrics입니다.
CloudWatch가 이 데이터를 받아들이는 방식이 흥미로웠습니다. 별도의 에이전트 없이 https://monitoring.<region>.amazonaws.com/v1/metrics 형태의 네이티브 OTLP HTTP 엔드포인트를 열어두고, Bearer 토큰(AWS SigV4로도 가능) 인증만 통과하면 CloudWatch OTel Metrics로 수집합니다. 내부적으로는 이 메트릭이 CloudWatch의 OTel Metrics(신형 저장소)로 들어가서 PromQL로 조회 가능한 상태가 됩니다.
Coding Agent Insights 대시보드가 “기본 제공된다”는 말에는 트릭이 있습니다. 대시보드가 기대하는 메트릭 이름(예: claude_code.token.usage, claude_code.cost.usage 등)과 차원(dimension)이 있고, 조직적 속성인 user.email, team.id, department, cost_center 같은 값은 반드시 OTel resource attribute로 실려 와야 합니다. Metric attribute로 넣으면 대시보드의 슬라이스 필터에 잡히지 않습니다. 이 부분이 문서에서도 “Important”로 강조돼 있었는데, 실제로 처음에 metric attribute로 넣었다가 대시보드가 비어 보여서 한참 헤맸습니다.
AWS 측 구성은 단순합니다. Node.js와 Claude Code CLI가 도는 환경(로컬 노트북이든 EC2든 무관)에서, IAM 역할 대신 CloudWatch Metrics API Key(cloudwatch:PutMetricData 등 지표 전송 권한을 가진 IAM 사용자로부터 생성) 형태의 Bearer 토큰을 발급해 사용했습니다. 이 토큰은 모델 추론에 쓰는 Bedrock API Key와는 별개이며, 텔레메트리 전송 경로 인증에만 쓰입니다.
(B) 주요 이점과 고려 사항
가장 먼저 눈에 띈 것은 대시보드가 이미 “쓸 만한” 카테고리로 나뉘어 있다는 점이었습니다. 토큰 사용량은 input/output/cacheRead/cacheCreation 네 가지 type으로 자동 분리되고, 모델별(model 차원), 사용자별, 팀별로 자유롭게 grouping이 됩니다. 테스트 계정에서 세 개의 가짜 팀(platform, data, frontend)을 만들어 돌려봤더니, 어느 팀이 Sonnet 대비 Opus를 많이 쓰고 있는지, cache hit ratio가 어느 수준인지 그래프로 바로 보였습니다.
실제로 세 개의 가짜 팀으로 세션을 돌려보니, 단발 세션에서는 Total Tokens 33.9K 수준이던 것이 팀별로 나눠 세 세션을 돌리자 99.1K / 3 users / 3 sessions로 집계됐고, Group by Team으로 바꾸자 팀별 토큰 사용량이 색깔별 그래프로 바로 갈렸습니다.
프롬프트 스타일과 사용량의 관계도 흥미로운 단서였습니다. “관련 파일을 먼저 찾아본 뒤 수정해줘”처럼 탐색을 유도하면 세션당 토큰과 turn 수가 늘고, 컨텍스트를 미리 붙여주면 줄어드는 경향이 metric에서 드러났습니다.
운영상 고려할 점도 있었습니다. 첫째, 개발자 로컬 머신에서 직접 CloudWatch로 전송하게 하려면 Bearer 토큰을 배포해야 하는데, 이 장기 자격증명이 로컬 셸 환경에 남는 것을 어떻게 관리할지가 이슈입니다.
비용 측면도 예상보다 신경 쓸 부분이 있었습니다. CloudWatch OTel Metrics는 unique time series 개수가 아니라 수집한 비압축 OTLP payload 용량(GB)을 기준으로 과금됩니다. attribute가 많아질수록 datapoint 크기가 커지고, PromQL query가 스캔하는 sample 수도 늘어날 수 있어, 카디널리티는 여전히 비용과 query 성능 측면에서 관리해야 합니다.
마지막으로, “어떤 파일을 주로 수정했는가”, “어떤 언어에서 tool 실행이 실패하는가” 같은 세밀한 분석은 기본 대시보드에서는 불가능합니다. tool 실행 결과는 metrics가 아니라 event/log 신호라 별도 수집이 필요합니다. 기본 대시보드는 조직 전반의 adoption과 cost overview에 적합했고, PromQL 커스텀 뷰는 엔지니어링 리드용으로 나눠 쓰는 게 자연스러웠습니다.
시그널 구분: metrics / events / traces
Claude Code의 OTel 신호는 섞어서 이해하면 안 됩니다.
| Signal | 내용 | 활성화 |
|---|---|---|
| Metrics | 토큰, 비용, 세션, 코드 변경 등 | OTEL_METRICS_EXPORTER |
| Events / Logs | API 요청, tool result, tool decision 등 | OTEL_LOGS_EXPORTER |
| Traces | Prompt → API → Tool 실행 관계 | 별도 beta opt-in 필요 |
이 글의 설정은 metrics exporter만 활성화하므로 tool result event나 trace는 CloudWatch로 전송되지 않습니다.
프라이버시 기본값도 짚어둘 만합니다. Claude Code 공식 문서 기준 기본적으로 프롬프트 원문, 어시스턴트 응답 원문, tool input과 파일 내용은 텔레메트리에 수집되지 않습니다. 다만 OAuth 인증 시 user.email은 telemetry에 포함될 수 있으니, 개인 식별자 노출을 원치 않으면 team.id까지만 붙이는 절충안을 고려할 수 있습니다.
(C) 아키텍처 트레이드오프
첫 번째: collector를 중간에 둘지, 에이전트가 직접 CloudWatch로 전송하게 할지
표준 OTel 프랙티스에 따르면 OpenTelemetry Collector를 EC2나 ECS Fargate에 띄워두고 각 개발자 머신은 그쪽으로 로컬 네트워크 송신을 하는 게 정석입니다. 하지만 코딩 에이전트의 실행 위치가 개인 노트북, 원격 devcontainer, GitHub Codespaces 등으로 분산돼 있어서 공통 접점을 만들기 어려웠습니다. 결국 이번 PoC에서는 CLI가 CloudWatch OTLP 엔드포인트로 직접 전송하는 방식을 택했습니다.
두 번째: 인증 방식
Bearer 토큰과 SigV4(IAM) 두 가지 옵션이 있는데, 로컬 CLI 환경에서는 Bearer 토큰이 훨씬 다루기 쉽습니다. IAM은 EC2/ECS 같은 AWS 내부 리소스에서 실행할 때 자연스럽지만, 개인 노트북에서 IAM 자격증명을 관리하려면 aws-vault 같은 도구가 추가로 필요합니다. 실제 조직 배포라면 SSO 기반 enterprise 경로를 강력히 추천합니다.
세 번째: resource attribute를 어디까지 표준화할지
처음에는 user.email, team.id, cost_center만 넣으려 했는데, 커스텀 attribute(project.repo 등)는 기본 대시보드에는 노출되지 않고 PromQL 커스텀 쿼리에서만 쓸 수 있습니다. 대시보드 표준 슬라이스를 최대한 활용하려면 문서에 명시된 attribute set만 넣고, 그 외는 label sprawl로 이어질 수 있으니 자제하는 게 낫다는 결론이었습니다.
네 번째: 개발자 프라이버시와 관측 가능성 사이의 균형
user.email을 붙이면 개인 단위 분석이 가능해지지만, team.id까지만 붙이고 개인 식별자는 제외하는 방식도 테스트해봤는데, “누가 많이 쓰는가”보다 “어느 팀이 어떻게 쓰는가”에 초점을 맞춘다면 이 절충안이 실용적이었습니다.
코드 예시
Claude Code가 CloudWatch OTLP 엔드포인트로 메트릭을 전송하도록 만드는 최소 환경 변수 세팅입니다. 핵심은 OTEL_RESOURCE_ATTRIBUTES에 조직 속성을 실어 보내는 것, 그리고 Claude Code는 metrics 전용 환경 변수에 /v1/metrics까지 전체 경로를 명시해야 한다는 점입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Claude Code OTel 메트릭을 CloudWatch로 직접 전송
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
# metrics 전용 변수 + /v1/metrics 전체 경로
# (Claude Code는 경로를 자동으로 붙이지 않음)
export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT="https://monitoring.ap-northeast-2.amazonaws.com/v1/metrics"
export OTEL_EXPORTER_OTLP_METRICS_HEADERS="Authorization=Bearer ${CW_OTLP_TOKEN}"
# (선택) export 주기 단축 - 짧은 세션에서 값이 빨리 뜨게
export OTEL_METRIC_EXPORT_INTERVAL=2000
# 리소스 속성 - 대시보드 슬라이스에 반드시 resource로 실려야 함
# 주의: 값 사이에 공백이 들어가면 안 됨
export OTEL_RESOURCE_ATTRIBUTES="service.name=claude-code,user.email=hong@example.com,team.id=platform,department=engineering,cost_center=cc-1024,organization=acme"
EC2에서 여러 개발자 프로파일을 흉내내기 위해 팀별 프로파일을 자동 생성하는 스크립트입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
# 팀별 개발자 프로파일 생성 (PoC 시뮬레이션용)
for TEAM in platform data frontend; do
for USER in alice bob; do
PROFILE_FILE="/home/${USER}-${TEAM}/.claude_env"
mkdir -p "$(dirname "$PROFILE_FILE")"
cat > "$PROFILE_FILE" <<EOF
export OTEL_RESOURCE_ATTRIBUTES="service.name=claude-code,user.email=${USER}@acme.test,team.id=${TEAM},department=engineering,cost_center=cc-${TEAM},organization=acme"
export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT="https://monitoring.ap-northeast-2.amazonaws.com/v1/metrics"
export OTEL_EXPORTER_OTLP_METRICS_HEADERS="Authorization=Bearer ${CW_OTLP_TOKEN}"
EOF
done
done
보안 주의: 공용 EC2 환경에서 장기 CloudWatch Metrics API Key를 world-readable 평문 파일에 심는 방식은 권장하지 않습니다. 공용 서버라면 Collector가 EC2 Instance Role로 SigV4 인증하고, 사용자에게는 장기 키를 노출하지 않는 구조가 더 안전합니다.
PromQL로 팀별 시간당 토큰 소비량을 직접 조회하는 예시입니다. (1) CloudWatch PromQL은 OTel metric 이름의 점(.) 표기를 그대로 유지하므로 큰따옴표로 감싼 셀렉터를 씁니다. (2) resource attribute는 @resource. 접두사 레이블로 매핑됩니다.
# 팀별 최근 1시간 output 토큰 소비 총량 (Query Studio에서 실행)
# rate()는 초당 평균 증가율이라 "시간당 총량"과 안 맞음 → increase() 사용
sum by ("@resource.team.id", model) (
increase({
"claude_code.token.usage",
type="output"
}[1h])
)
CloudWatch alarm으로 특정 팀의 토큰 소비가 급증할 때 알림을 받는 설정입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# PromQL 기반 CloudWatch alarm 생성
aws cloudwatch put-metric-alarm \
--alarm-name "claude-code-token-surge-platform" \
--alarm-description "Platform 팀의 최근 1시간 토큰 사용량 급증 감지" \
--evaluation-criteria '{
"PromQLCriteria": {
"Query": "sum(increase({\"claude_code.token.usage\", \"@resource.team.id\"=\"platform\"}[1h])) > 500000",
"PendingPeriod": 600,
"RecoveryPeriod": 300
}
}' \
--evaluation-interval 300 \
--alarm-actions arn:aws:sns:ap-northeast-2:123456789012:cost-alerts \
--region ap-northeast-2
PromQL alarm 문법은 AWS CLI 버전에 민감하므로, 재현 시 최신 CLI 사용을 권장합니다.
Environment & Final Checklist
| 항목 | 값 |
|---|---|
| Region | ap-northeast-2 |
| Claude Code | 2.1.220 |
| AWS CLI | 2.25.14 |
| Compute | Local |
| Model 추론 | kiro-gateway 경유, 관측 경로와 독립 |
| Teams | platform, data, frontend |
| Telemetry | Metrics only, direct OTLP |
| Auth | CloudWatch Metrics API Key |
| Test period | 1h |
재현하려는 분들을 위한 체크리스트입니다.
- CloudWatch OTLP 엔드포인트용 Bearer 토큰(CloudWatch Metrics API Key) 또는 IAM 자격증명 준비
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT에https://monitoring.<region>.amazonaws.com/v1/metrics전체 경로 세팅OTEL_EXPORTER_OTLP_METRICS_HEADERS에Authorization=Bearer <토큰>세팅OTEL_RESOURCE_ATTRIBUTES에user.email,team.id,department,cost_center,organization포함 (값 사이 공백 없이)- Claude Code라면
CLAUDE_CODE_ENABLE_TELEMETRY=1활성화 - 콘솔의 GenAI Observability → Coding Agent Insights에서 값 확인
- Query Studio에서 PromQL(
increase,@resource.접두사)로 커스텀 뷰 시험 - 시간당 토큰 alarm 하나 정도는 걸어두기 (비용 급증 방지)
- 테스트 후 API Key 폐기 절차 수행
Lessons Learned
가장 인상적이었던 것은 “관측 가능성 자체를 도구 벤더가 담당하는” 흐름이었습니다. Claude Code나 Codex 같은 도구가 OTel을 기본 탑재하는 시대에는, 이걸 어떻게 계측할지 고민할 필요 없이 “어디로 보낼 것인가”만 결정하면 됩니다. AWS는 여기서 표준 OTLP 엔드포인트를 그대로 열어두는 방식으로 참여했습니다. 다만 “완전한 벤더 중립”이라기보다 “전송 계층은 표준, 관측 계층은 관리형”이라는 균형으로 이해하는 게 정확합니다.
조직 속성을 resource attribute로 넣어야 한다는 규약은 처음에는 사소해 보였지만, 실제로는 팀 전체가 지켜야 할 스키마 계약(schema contract)이라는 점이 인상 깊었습니다. 각 개발자가 임의로 attribute를 붙이기 시작하면 payload가 커지고 query 성능과 비용에 영향을 주므로, .claude_env 같은 공용 프로파일을 조직 차원에서 관리하는 편이 안전합니다.
마지막으로, 코딩 에이전트 관측 데이터는 단순한 비용 리포팅 이상의 가치가 있었습니다. 토큰 사용 패턴이나 cache hit ratio를 보고 있으면, 개발자가 프롬프트를 어떻게 구성하는지에 대한 힌트가 나옵니다. 이걸 조직 내 프롬프트 가이드나 코칭 자료로 되먹임할 수 있다면, 관측 데이터가 곧 생산성 개선 루프의 입력이 되는 그림이 그려집니다.






