~/infra-dev.md
INFRA_DEV

관측 태그는 왜 로그 문구가 아니라 알림 계약일까: OpenTelemetry Semantic Conventions 1.42로 보는 카디널리티 관리

10분 읽기·2026.07.11·출처 4·00
오늘의 질문

OpenTelemetry 속성 이름 하나가 대시보드 비용과 장애 알림 신뢰도를 어떻게 바꿀까?

infra-dev.md
관측 태그 계약

관측 태그는 왜 로그 문구가 아니라 알림 계약일까: OpenTelemetry Semantic Conventions 1.42로 보는 카디널리티 관리

1. 왜 지금 봐야 하나

관측성은 보통 “로그를 더 남기자”, “트레이스를 붙이자”, “대시보드를 만들자”로 시작한다. 그런데 운영 단계로 가면 더 중요한 질문이 생긴다.

이 필드 이름과 라벨 조합을 앞으로 1년 동안 알림, 비용, 장애 분석의 기준으로 믿어도 될까?

OpenTelemetry Semantic Conventions 1.42.0 릴리스는 이 질문을 아주 현실적으로 보여준다. 릴리스에는 세 가지 신호가 같이 들어 있다.

첫째, gen_ai.* 속성·메트릭·이벤트·스팬이 기존 semantic-conventions 저장소에서 deprecated 처리되고 별도 semantic-conventions-genai 저장소로 이동했다. AI 호출 관측이 빠르게 커지면서 GenAI만의 스키마 생명주기를 분리한 셈이다.

둘째, Kubernetes와 container registry의 일부 resource attribute가 stable로 승격됐다. 이제 컨테이너·쿠버네티스 리소스를 설명하는 몇몇 필드는 “실험용 이름”이 아니라 대시보드와 알림이 의존해도 되는 계약에 가까워졌다.

셋째, HTTP client metric의 network.peer.address가 일부 메트릭에서 Recommended가 아니라 Opt-In으로 바뀌었다. 이유는 명확하다. 원격 IP 주소는 높은 카디널리티를 만들기 쉽고, cumulative temporality로 내보내면 프로세스 생애 동안 time series가 계속 늘어날 수 있기 때문이다.

작은 팀에게 이 변화는 “OpenTelemetry 버전 뉴스”가 아니다. 관측 데이터도 API처럼 버전, 안정성, 카디널리티 예산, 마이그레이션 계획이 필요하다는 신호다.

2. 핵심 개념

Semantic Convention은 “관측 데이터의 변수명 규칙” 정도로 보이지만, 실제 역할은 더 크다.

OpenTelemetry 문서는 Semantic Conventions를 span name, metric instrument와 unit, attribute name/type/meaning/valid value를 정의하는 공통 규칙이라고 설명한다. 이 규칙을 따르면 여러 코드베이스, 라이브러리, 플랫폼에서 같은 의미의 데이터를 같은 이름으로 모을 수 있다.

즉 semantic convention은 다음 세 주체 사이의 계약이다.

  1. 계측 코드: 어떤 span, metric, log attribute를 찍을지 정한다.
  2. 수집·저장 파이프라인: Collector, backend, retention, sampling, aggregation 정책을 적용한다.
  3. 소비자: 대시보드, SLO, 알림, incident query, 비용 분석이 그 필드 이름을 믿고 동작한다.

여기서 중요한 단어가 안정성이다. OpenTelemetry의 versioning and stability 문서는 신호가 Development → Stable → Deprecated → Removed 생명주기를 가진다고 설명한다. Development 단계의 신호는 breaking change가 생길 수 있고, 장기 의존을 피해야 한다. Stable 단계가 되면 장기 의존을 걸 수 있다.

운영 관점으로 번역하면 이렇다.

  • Development attribute: 실험용 대시보드에는 써도 되지만, 24시간 깨우는 pager 조건에 바로 넣으면 위험하다.
  • Stable attribute: SLO, alert, 비용 집계, 장기 dashboard의 기준으로 삼을 수 있다.
  • Deprecated attribute: 바로 삭제하지 말고 “읽기는 하되 새로 쓰지 않는” 전환 기간이 필요하다.
  • Moved convention: 필드 이름뿐 아니라 schema URL, instrumentation package, 문서 링크까지 바뀔 수 있다.

3. 최신 이슈와 연결

이번 OpenTelemetry 1.42.0에서 특히 배울 점은 “좋은 관측 필드도 너무 자세하면 장애가 된다”는 것이다.

network.peer.address가 Opt-In이 된 이유

릴리스 노트는 network.peer.address가 high-cardinality인 경우가 많고, remote IP별로 time series가 생겨 cumulative temporality와 만나면 metric stream이 프로세스 생애 동안 계속 늘 수 있다고 설명한다. 그래서 http.client.open_connections, http.client.connection.duration에서 requirement level이 Recommended에서 Opt-In으로 바뀌었다.

이건 단순한 이름 변경이 아니다. 알림 품질과 비용 모델의 문제다.

예를 들어 외부 API를 호출하는 서비스가 있다고 하자. method, status_code, route 정도로 묶으면 시계열 수가 제한된다. 그런데 여기에 network.peer.address가 들어가면 원격 IP가 바뀔 때마다 새로운 시계열이 생긴다. CDN, 로드밸런서, SaaS API, 동적 egress 경로를 만나면 IP 수가 빠르게 늘 수 있다.

결과는 세 가지다.

  • 메트릭 저장 비용이 올라간다.
  • 쿼리가 느려지고 대시보드가 무거워진다.
  • 알림 기준이 “서비스 단위 문제”가 아니라 “무수한 IP 조각”으로 흩어진다.

그래서 Opt-In은 기능 축소가 아니라 운영 기본값을 안전하게 바꾸는 선택이다.

GenAI convention 분리는 AI 관측의 생명주기 분리다

gen_ai.*가 별도 저장소로 이동한 것도 중요하다. AI 호출 관측은 모델명, provider, token usage, tool call, MCP, latency, fallback, safety event처럼 변화가 빠른 필드를 다룬다. 기존 안정화 속도와 같은 저장소에서 움직이면 너무 빠르거나 너무 느릴 수 있다.

별도 저장소는 이런 의미를 가진다.

  • GenAI 관측은 빠르게 바뀔 수 있으므로 schema URL과 문서 출처를 명확히 봐야 한다.
  • AI gateway, model fallback, provider routing을 운영하는 팀은 gen_ai.* 필드를 “그냥 태그”가 아니라 버전 있는 계약으로 관리해야 한다.
  • 대시보드와 알림은 특정 convention 버전에 묶여 있을 수 있으므로 업그레이드 때 비교 테스트가 필요하다.

Kubernetes resource attribute stable 승격

Kubernetes와 container registry resource attribute 일부가 stable로 승격된 점은 반대 방향의 신호다. 컨테이너 기반 운영에서는 pod, node, namespace, container image 같은 차원이 장애 분석의 기본 축이다. stable 승격은 이 축들이 장기 대시보드와 알림의 공통 언어로 굳어지고 있다는 뜻이다.

4. 개발자 관점 해석

개발자는 관측성을 “나중에 SRE가 보는 것”으로 미루기 쉽다. 하지만 AI 시대의 개발자는 운영 데이터를 직접 읽고, 자동화된 에이전트나 알림이 잘못된 결론을 내리지 않도록 데이터 계약을 설계해야 한다.

여기서 필요한 태도는 세 가지다.

1) Attribute는 로그 문구가 아니라 API 필드다

로그 문구는 사람이 읽고 끝낼 수 있다. 하지만 metric label과 trace attribute는 쿼리, 알림, 비용 집계, 자동 분석이 의존한다. 이름을 바꾸거나 카디널리티를 늘리는 일은 API breaking change와 비슷하다.

따라서 새 attribute를 추가할 때는 코드 리뷰에서 이렇게 물어야 한다.

  • 이 필드는 bounded cardinality인가?
  • user id, request id, raw URL, IP, email 같은 무한 차원을 넣고 있지 않은가?
  • alert 조건에 쓸 stable field인가, 임시 디버깅 field인가?
  • 제거하거나 이름을 바꿀 때 dashboard owner를 알 수 있는가?

2) Stable과 Development를 같은 무게로 쓰지 않는다

OpenTelemetry 문서의 stability lifecycle은 “문서에 있는 이름이면 다 안전하다”는 착각을 막아준다. Development 상태의 convention은 바뀔 수 있다. 특히 GenAI처럼 빠르게 변하는 영역에서는 오늘 만든 dashboard가 다음 convention 이동에서 깨질 수 있다.

운영적으로는 stable field와 experimental field를 나눠야 한다.

  • stable field: SLO, pager alert, 월별 비용 리포트에 사용
  • experimental field: 임시 dashboard, canary, 내부 분석에 사용
  • deprecated field: dual-read 기간을 두고 제거 계획 수립

3) 카디널리티 예산을 명시한다

관측 비용은 “데이터 양”보다 “시계열 수”에서 폭발하는 경우가 많다. network.peer.address Opt-In 변경은 이 점을 잘 보여준다.

팀 단위로는 다음처럼 예산을 둘 수 있다.

  • HTTP client metric 기본 label: service, method, status_code, target service 정도로 제한
  • IP, full URL, user id, request id는 metric label 금지
  • 필요하면 trace attribute나 log field로 남기되 sampling/retention을 다르게 적용
  • 예외적으로 metric label에 넣을 때는 만료일과 owner를 기록

5. 내 프로젝트에 적용할 체크포인트

아래 체크리스트를 오늘 프로젝트에 그대로 적용해보자.

계측 코드

  • metric label에 user_id, request_id, email, raw path, raw query string, IP address가 들어가지 않는가?
  • HTTP client metric에서 원격 주소 차원이 정말 필요한가, 아니면 service name이나 peer service로 충분한가?
  • AI 호출 관측을 하고 있다면 gen_ai.* convention의 현재 저장소와 schema URL을 확인했는가?
  • Kubernetes resource attribute를 직접 문자열로 만들지 않고 SDK/instrumentation 기본값을 우선 쓰는가?

대시보드와 알림

  • pager alert가 Development 상태의 convention이나 deprecated field에 의존하지 않는가?
  • dashboard query에 너무 많은 group-by가 들어가 비용을 키우지 않는가?
  • convention 업그레이드 때 깨질 dashboard 목록을 찾을 수 있는가?
  • alert label에는 사람이 조치 가능한 차원만 남겼는가?

파이프라인과 비용

  • Collector나 backend에서 high-cardinality attribute를 drop/transform할 정책이 있는가?
  • metric cardinality 상위 N개를 주기적으로 보는가?
  • trace/log와 metric의 보존 기간을 다르게 가져가는가?
  • 새 instrumentation 도입 전 staging에서 시계열 증가량을 측정하는가?

6. 오늘 10분 액션

오늘은 코드를 크게 바꾸지 말고 “관측 태그 감사”만 해보자.

  1. 최근 7일간 가장 비싼 metric 또는 가장 많은 time series를 만든 metric 5개를 찾는다.
  2. 각 metric의 label 목록을 본다.
  3. label을 세 그룹으로 표시한다.
    • 안정적이고 bounded: service.name, http.request.method, http.response.status_code
    • 조심해야 함: url.path, network.peer.address, container.id
    • metric label 금지 후보: user_id, request_id, raw URL, email, token, session id
  4. 금지 후보가 있으면 metric에서는 제거하고 trace/log로 옮길 수 있는지 본다.
  5. “pager alert에 써도 되는 stable field 목록”을 README나 runbook에 5줄로 적는다.

작은 예시는 이렇다.

zsh — 생존확인.sh
Metric label policy
- OK for alerts: service.name, deployment.environment, http.request.method, http.response.status_code, k8s.namespace.name
- Avoid by default: network.peer.address, url.full, container.id
- Never in metric labels: user_id, request_id, email, access_token, raw query string
- Experimental conventions require dashboard owner and review date
- Deprecated conventions require dual-read migration plan

이 10분 작업만 해도 다음 장애 때 “왜 알림이 수천 개로 쪼개졌지?”라는 질문을 줄일 수 있다.

7. 더 볼 자료

중복 회피 메모

로컬 content/generated와 Supabase의 최근 infra_dev 글을 확인했다. 최근 글은 RDS PostgreSQL delayed replica/PITR, GitHub secret scanning triage, Vercel AI Gateway routing/fallback, GitHub Actions pull_request_target와 OIDC subject/audience, Kubernetes Indexed Job 실패 예산, CI 네트워크 failover, EventBridge logging, Lambda durable functions, Cloudflare Queues backlog/DLQ, OpenTelemetry Collector 운영을 다뤘다. 이번 글은 Collector 배포나 큐 backpressure가 아니라 OpenTelemetry Semantic Conventions 1.42.0의 GenAI convention 분리, Kubernetes resource attribute 안정화, network.peer.address Opt-In 변경을 바탕으로 관측 attribute를 알림·비용·마이그레이션 계약으로 관리하는 방법에 집중해 중복을 피했다.

오늘 10분 액션+5%

댓글 0

최신순 ▾
한 줄 남기기

혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)