OpenMetrics 2.0 사양
OpenMetrics 2.0 사양 (OpenMetrics 2.0 specification)
OpenMetrics 2.0의 공식 사양 문서예요. 이전 1.0 사양을 기반으로 하면서, 더 큰 신뢰성·사용성·현대 프로메테우스 데이터 모델과의 일관성을 위해 강화된 다음 버전이에요. 특히 OpenTelemetry 데이터 모델과의 호환성도 개선됐어요. 합성 값(CompositeValue) 도입, 클래식/네이티브 버킷 표현, 텍스트 형식의 재정의 등 변화가 큽니다.
이 문서는 그 자체로 완결된(standalone) 사양으로 사용되도록 설계됐어요. 2026년 3월 현재 release candidate(rc0)이며 실험 상태예요. RFC 2119/8174 규범 언어를 따라 요구사항을 표현하므로, 구현 시 그대로 따르면 되는 구조예요.
출처: 문서
본문
- 버전: 2.0.0-rc0
- 상태: 실험(Experimental)
- 날짜: 2026년 3월
- 저자: Arthur Silva Sens, Bartłomiej Płotka, David Ashpole, György Krajcsovits, Owen Williams, Richard Hartmann
- 명예 저자(Emeritus): Ben Kochie, Brian Brazil, Rob Skillington
2012년에 만들어진 프로메테우스는 2015년부터 클라우드 네이티브 관측성의 기본 도구가 됐어요. 프로메테우스 설계의 핵심 부분은 텍스트 메트릭 exposition 형식이며, 2014년부터 안정된 Prometheus exposition format 0.0.4라고 불러요. 이 형식에서는 생성, 수집, 사람이 이해하기 쉽도록 특별히 신경을 썼어요. 2020년 기준으로 공개적으로 등록된 exporter가 700개 이상 있고, 등록되지 않은 exporter는 알 수 없는 수만큼 있으며, 이 형식을 사용하는 수천 개의 네이티브 라이브러리 연동이 있어요. 다양한 프로젝트와 회사의 수십 개 수집기가 이를 소비하도록 지원해요.
2020년에 OpenMetrics 1.0이 사양을 정리하고 강화하기 위해 출시됐고, 추가 목적은 IETF로 가져가는 것이었어요. OpenMetrics 1.0 텍스트 exposition은 수십 개의 exporter, 연동, 수집기 사이에서 널리 유기적으로 채택된 실무 표준을 문서화했어요.
약 2024년경 OpenMetrics 프로젝트가 CNCF 프로메테우스 프로젝트 우산 아래로 통합됐어요. OpenMetrics 1.0을 넓은 규모로 배포하면서 얻은 프로덕션 경험과, 텍스트 형식에 빠져 있던 새로운 프로메테우스 혁신의 백로그를 함께 고려해, 프로메테우스 커뮤니티는 OpenMetrics 표준의 두 번째 버전을 추진하기로 결정했어요.
OpenMetrics 2.0의 의도는 OpenMetrics 1.0을 기초로 사용하고, 사용 용이성과 가독성을 희생하지 않으면서 더 큰 신뢰성, 사용성, 현대 프로메테우스 데이터 모델과의 일관성을 달성하도록 강화하는 것이에요. OpenMetrics 2.0은 또한 OpenTelemetry 데이터 모델과 명명 규칙과의 호환성도 개선해요.
이 문서는 그 자체로 독립된(standalone) 사양으로 사용되도록 설계됐어요.
참고: 이것은 OpenMetrics 2.0 사양의 릴리스 후보(RC) 버전이에요. 이는 이 사양이 현재 실험 상태라는 뜻이에요 - 큰 변경은 예상되지 않지만, 초기 채택자의 피드백에 기반해 필요하면 호환성을 깨뜨릴 권리를 보유해요. 잠재적 피드백, 질문, 제안은 prometheus/openmetrics 저장소에 이슈로 추가해야 해요.
개요 (Overview)
메트릭은 특정한 종류의 텔레메트리 데이터예요. 일련의 데이터에 대한 현재 상태의 스냅샷을 나타내요. 개별 사건에 대한 기록이나 정보에 초점을 맞춘 로그나 이벤트와는 구별돼요.
OpenMetrics는 주로 와이어 형식이며, 그 형식에 대한 특정 전송과는 독립적이에요. 그 형식은 정기적으로 소비되고 연속적인 exposition에 걸쳐 의미가 있도록 기대돼요.
구현자는 주어진 프로세스나 장치에 대해 문서화된 URL에 대한 HTTP GET 요청에 응답해 OpenMetrics 텍스트 형식으로 메트릭을 노출해야(SHOULD) 해요. 이 엔드포인트는 "/metrics"라고 불러야(SHOULD) 해요. 구현자는 HTTP를 통해 운영자 구성 엔드포인트로 메트릭 세트를 정기적으로 푸시하는 것 같은 다른 방식으로도 OpenMetrics 형식 메트릭을 노출할 수(MAY) 있어요.
메트릭과 시계열
이 표준은 모든 시스템 상태를 수치 값으로 표현해요. 카운트, 현재 값, 분포, 열거, 불리언 상태가 흔한 예시예요. 메트릭과 달리 단일 사건은 특정 시간에 발생해요. 메트릭은 데이터를 시간적으로 집계하고 시스템 상태의 샘플을 제공하는 경향이 있어요. 이것은 정보를 잃을 수 있지만, 오버헤드 감소는 많은 현대 모니터링 시스템에서 흔히 선택되는 엔지니어링 트레이드오프예요.
시계열은 시간에 따라 변하는 정보의 기록이에요. 메트릭 시계열의 흔한 예는 네트워크 인터페이스 카운터, 장치 온도, BGP 연결 상태, 지연 시간 분포, 알림 상태예요.
규범 언어 (Normative Language)
이 문서의 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", "OPTIONAL" 키워드는 여기에 표시된 것처럼 모두 대문자로 나타날 때에만 RFC 2119와 RFC 8174에서 설명된 대로 해석해야 해요.
"RESERVED"라는 단어는 미래 사용이나 이 표준 자체의 사용을 위해 따로 둔 값, 이름, 필드를 지정하는 데 사용돼요. "RESERVED"로 설명된 값, 이름, 필드는 이 표준이나 미래 버전이 명시적으로 허용하지 않는 한 사용해서는 안(MUST NOT) 돼요.
데이터 모델
이 섹션은 ABNF 섹션과 함께 읽어야(MUST) 해요. 둘 사이에 불일치가 있으면 ABNF의 제약이 우선해야(MUST) 해요.
데이터 타입
샘플 값 (Sample Values)
OpenMetrics의 메트릭 값은 Number 또는 CompositeValue여야(MUST) 해요.
Number
Number 값은 부동 소수점이거나 정수여야(MUST) 해요.
수집기가 float64만 지원할 수도(MAY) 있다는 점에 유의하세요. 예를 들어 Go의 float64는 약 15-17개의 유효 십진 자릿수 정밀도를 가진 IEEE 754-2008 배정밀도(binary64) 부동 소수점 숫자예요. NaN, +Inf, -Inf 같은 비실수 값을 지원해야(MUST) 해요. NaN 값을 누락 값으로 간주해서는 안(MUST NOT) 되지만, 0으로 나누기나 정의되지 않거나 부정확한 결과를 내는 다른 수학 연산을 신호하는 데 사용할 수(MAY) 있어요.
불리언은 1이 true이고 0이 false인 Number 값으로 표현되어야(MUST) 해요.
CompositeValue
CompositeValue는 MetricFamily 내의 Metric에 대한 샘플 값을 재생성하는 데 필요한 모든 정보를 포함해야(MUST) 해요.
다음 MetricFamily 타입은 메트릭 값에 CompositeValue를 사용해야(MUST) 해요:
- Histogram MetricFamily 타입
- GaugeHistogram MetricFamily 타입
- Summary MetricFamily 타입
다른 MetricFamily 타입은 Number를 사용해야(MUST) 해요.
타임스탬프 (Timestamps)
타임스탬프는 초 단위의 Unix Epoch여야(MUST) 해요. 타임스탬프는 초 미만 정밀도(예: 밀리초나 마이크로초)를 나타내기 위해 부동 소수점이어야(SHOULD) 해요. 음수 타임스탬프를 사용할 수(MAY) 있어요.
이 표준에서 타임스탬프를 사용하는 곳은 몇 군데야:
- Exemplar의 타임스탬프
- 샘플의 타임스탬프
- 샘플의 시작 타임스탬프
문자열 (Strings)
문자열은 유효한 UTF-8 문자로만 구성되어야(MUST) 하고 길이가 0일 수(MAY) 있어요. NULL(ASCII 0x0)을 지원해야(MUST) 해요.
레이블 (Label)
레이블은 문자열로 구성된 키-값 쌍이에요.
하나 이상의 밑줄로 시작하는 레이블 이름은 RESERVED(예약)이며, 이 표준이 지정하지 않는 한 사용해서는 안(MUST NOT) 돼요. 그런 레이블 이름은 메트릭 연합(federation) 같은 경우에서 MetricFamily의 메타데이터가 서로 충돌할 수 있을 때 TYPE과 UNIT 메타데이터 대신 사용될 수(MAY) 있어요.
레이블 이름은 ABNF 섹션의 label-name 항목의 제약을 따라야(SHOULD) 해요. 레이블 이름은 ABNF 섹션에서 설명한 대로 인용되고 이스케이프된 UTF-8 문자열일 수(MAY) 있어요. UTF-8 메트릭을 노출하면 사용성이 떨어질 수 있다는 점을 유의하세요.
빈 레이블 값은 레이블이 없는 것처럼 취급해야(SHOULD) 해요.
LabelSet
LabelSet은 Label로 구성되어야(MUST) 하며 비어 있을 수(MAY) 있어요. 레이블 이름은 LabelSet 내에서 고유해야(MUST) 해요.
Exemplar
Exemplar는 MetricSet 외부 데이터에 대한 참조예요. 일반적인 사용 사례는 프로그램 트레이스의 ID예요.
Exemplar는 LabelSet과 Number 값으로 구성되어야(MUST) 하고 타임스탬프가 있어야(MUST) 해요. LabelSet은 Metric의 LabelSet에 포함된 레이블 이름을 포함해서는 안(SHOULD NOT) 돼요. 타임스탬프는 존재하면 샘플의 타임스탬프보다 앞이거나 같아야(SHOULD) 해요. 타임스탬프는 존재하면 샘플의 시작 타임스탬프보다 뒤이거나 같아야(SHOULD) 해요. 샘플의 Exemplar는 일관된 스타일을 가지도록 같은 레이블 이름을 가져야(SHOULD) 해요.
Exemplar의 타임스탬프는 관측된 시점에 가까워야(SHOULD) 하지만 정확할 필요는 없어요. 예를 들어 정확한 타임스탬프를 얻는 것이 비싸면 외부 소스나 추정치를 사용하는 것이 허용 가능해요.
Exemplar가 트레이스 컨텍스트를 참조할 때, trace-id 필드에는 trace_id 키를, parent-id 필드에는 span_id 키를 사용해야(SHOULD) 해요.
하드 제한이 지정되지는 않았지만, Exemplar의 LabelSet을 트레이스 스팬 세부 사항 같은 큰 데이터나 다른 이벤트 로깅을 운반하는 데 사용해서는 안(SHOULD NOT) 돼요.
수집기는 Exemplar의 LabelSet을 잘라내거나 Exemplar를 버릴 수(MAY) 있어요. LabelSet을 잘라낼 때 trace_id와 span_id는 잘라낸 후에도 보존되어야(SHOULD) 해요.
샘플 (Sample)
샘플은 Metric 내의 단일 데이터 포인트예요. 값이 있어야(MUST) 하고 타임스탬프가 있을 수(MAY) 있어요. MetricFamily 타입에 따라 Exemplar를 포함할 수 있고 시작 타임스탬프가 있을 수(MAY) 있어요.
샘플은 타임스탬프를 가지지 않는 것이 좋아요(SHOULD NOT). 권장되지 않는 이유는 타임스탬프 노출을 참조하세요. 존재하면 샘플의 타임스탬프는 값이 관측된 시점을 지정해요.
존재하면 샘플의 시작 타임스탬프는 측정 기간이 시작된 시점을 지정해야(SHOULD) 해요. 이는 수집기가 이전에 보지 못한 새 메트릭과 오래 실행 중인 메트릭을 구별하고, 카운터 값이 수집 사이에 감소하지 않았더라도 카운터 리셋을 감지하는 데 도움을 줄 수 있어요.
메트릭 (Metric)
메트릭은 MetricFamily 내의 고유한 LabelSet으로 정의돼요. 메트릭은 하나 이상의 샘플 목록을 포함해야(MUST) 해요. 메트릭에 대해 둘 이상의 샘플이 노출되면 해당 샘플은 단조 증가하는 타임스탬프를 가져야(MUST) 해요.
주어진 MetricFamily의 같은 이름을 가진 메트릭은 LabelSet에 같은 레이블 이름 세트를 가져야(SHOULD) 해요.
MetricFamily
MetricFamily는 메트릭이 0개 이상 있을 수(MAY) 있어요. MetricFamily의 모든 메트릭은 고유한 LabelSet을 가져야(MUST) 해요. MetricFamily는 이름을 가져야(MUST) 하고 Help, Type, Unit 메타데이터를 가져야(SHOULD) 해요.
이름 (Name)
MetricFamily 이름:
- 문자열이어야(MUST) 해요
- MetricSet 내에서 고유해야(MUST) 해요
- 패밀리의 모든 메트릭 이름과 같아야(MUST) 해요
참고: OpenMetrics 1.0은 MetricName에 필수 접미사를 요구했고, 그런 접미사 없이 일치하는 MetricFamily 이름을 요구했어요. 파서 신뢰성(즉 MetricFamily 메타데이터 일치)과 향후 호환성을 개선하기 위해, 이 사양은 메트릭 이름이 MetricFamily 이름과 엄격히 일치하도록 요구해요.
이름은 snake_case여야(SHOULD) 해요. 이름은 ABNF 섹션의 metricname 아래 제약을 따라야(SHOULD) 해요. MetricFamily 이름은 ABNF 섹션에서 설명한 대로 인용되고 이스케이프된 UTF-8 문자열일 수(MAY) 있어요. 특히 _total이나 단위 접미사가 이름에 포함되지 않으면 UTF-8 메트릭을 노출하면 사용성이 떨어질 수 있다는 점을 유의하세요.
MetricFamily 이름의 콜론은 해당 MetricFamily가 범용 모니터링 시스템의 계산 또는 집계 결과임을 신호하도록 RESERVED(예약)돼요.
하나 이상의 밑줄로 시작하는 MetricFamily 이름은 RESERVED(예약)이며 이 표준이 지정하지 않는 한 사용해서는 안(MUST NOT) 돼요.
권장되지 않는 접미사 (Discouraged Suffixes)
MetricFamily 이름은 _count, _sum, _gcount, _gsum, _bucket로 끝나서는 안(SHOULD NOT) 돼요. 특히 이름은 OpenMetrics 1.0 텍스트로 변환했을 때 메트릭 이름 충돌을 만들어서는 안(SHOULD NOT) 돼요. 수집기는 그런 MetricFamily로 MetricSet을 거부할 수(MAY) 있어요.
비준수 예는 foo_bucket이라는 gauge와 foo라는 histogram이에요. 이전 OpenMetrics 또는 텍스트 형식을 협상하는 exposer나 이전 데이터 모델만 지원하는 수집기는 결국 foo 히스토그램을 고전적 표현(foo_bucket, foo_count, foo_sum)으로 저장하고, 이것이 gauge와 충돌해 스크레이프 거부나 데이터 손실을 일으킬 수 있어요.
이 규칙은 이 사양이 "클래식" 표현 대신 합성 값으로의 프롬에테우스 생태계 전환을 따르고 있기 때문에 존재해요. 하지만 이 변환은 시간이 걸려요. 그런 접미사를 피하는 것은 이전 수집기와의 호환성과 궁극적인 마이그레이션 과정을 개선해요.
타입 (Type)
Type은 MetricFamily 타입을 지정해요. 유효한 값은 "unknown", "gauge", "counter", "stateset", "info", "histogram", "gaugehistogram", "summary"예요.
단위 (Unit)
Unit은 MetricFamily 단위를 지정해요. 비어 있지 않으면 밑줄로 분리된 MetricFamily 이름의 접미사여야(SHOULD) 해요. 타입별 추가 접미사는 단위 접미사 뒤에 온다. 단위가 MetricFamily 이름의 접미사가 아닌 메트릭을 최종 사용자에게 직접 노출하면 메트릭의 단위가 무엇인지 혼동이 생겨 사용성이 떨어질 수 있어요. 권장 단위 값은 단위와 기본 단위를 참조하세요.
Help
Help는 문자열이며 비어 있지 않아야(SHOULD) 해요. 사람이 소비할 MetricFamily의 간단한 설명을 제공하는 데 사용되며, 툴팁으로 사용될 만큼 짧아야(SHOULD) 해요.
MetricSet
MetricSet은 OpenMetrics가 노출하는 최상위 객체예요. MetricFamily로 구성되어야(MUST) 하며 비어 있을 수(MAY) 있어요.
각 MetricFamily 이름은 고유해야(MUST) 해요. 같은 레이블 이름과 값이 MetricSet의 모든 메트릭에 나타나서는 안(SHOULD NOT) 돼요.
MetricSet 내에서 MetricFamily의 특정 순서는 요구되지 않아요. Exposer는 사람이 읽기 쉽게 exposition을 만들 수(MAY) 있는데, 예를 들어 성능 트레이드오프가 말이 되면 알파벳순으로 정렬해요.
존재하면 아래 "푸시 기반과 풀 기반 시스템 모두에서 타깃 메타데이터 지원" 섹션에 따라 "target_info"라고 하는 Info MetricFamily가 처음이어야(SHOULD) 해요.
MetricFamily 타입
Gauge
게이지는 현재 측정값이에요. 현재 사용 중인 메모리 바이트나 큐의 항목 수 같은 것이에요. 게이지에서는 절대값이 사용자에게 관심사예요.
gauge 타입의 메트릭에 있는 샘플은 Number 값을 가져야(MUST) 해요.
게이지는 시간에 따라 증가, 감소, 또는 일정하게 유지될 수(MAY) 있어요. 한 방향으로만 움직여도 여전히 게이지일 수 있고 counter가 아닐 수 있어요. 로그 파일의 크기는 보통 증가만 하고, 리소스는 감소할 수 있으며, 큐 크기의 한계는 일정할 수 있어요.
Counter
카운터는 이산적인 사건을 측정해요. 흔한 예는 수신된 HTTP 요청 수, 사용된 CPU 초, 보낸 바이트예요. 카운터에서는 시간에 따라 얼마나 빨리 증가하는지가 사용자에게 관심사예요.
Counter용 MetricFamily 이름은 _total로 끝나야(SHOULD) 해요. _total 접미사 없는 메트릭을 노출하면 메트릭 타입이 무엇인지 혼동이 생겨 사용성이 떨어질 수 있어요.
Counter 타입의 메트릭에 있는 샘플은 시작 타임스탬프를 가져야(SHOULD) 해요.
Counter 타입의 메트릭에 있는 샘플은 NaN이 아닌 Number 값을 가져야(MUST) 해요. 값은 0으로 리셋되지 않는 한 시간에 따라 단조 비감소해야(MUST) 하고 0부터 시작해야 해요. 값은 0으로 리셋될 수(MAY) 있어요. 존재하면 해당 시작 타임스탬프도 대략적인 리셋 시간으로 설정되어야(MUST) 해요.
Counter 타입의 메트릭에 있는 샘플은 exemplar를 가질 수(MAY) 있어요.
StateSet
StateSet은 관련 불리언 값의 시리즈(비트셋이라고도 함)를 나타내요. ENUM을 인코딩해야 한다면 StateSet을 통해 할 수(MAY) 있어요.
StateSet은 상태마다 하나씩인 메트릭 세트로 구조화되며, 이를 StateSet MetricGroup이라 해요.
참고: OpenMetrics 1.0에서는 메트릭이 MetricPoint로 구성됐어요(예: Histogram 메트릭은 특별한 "le" 레이블로 각 버킷을 나타내는 MetricPoint를 가짐). OpenMetrics 2.0에서 더 이상 그렇지 않아요. OpenMetrics 1.0의 StateSet Metric은 OpenMetrics 2.0의 StateSet MetricGroup과 동등하고, OpenMetrics 1.0의 StateSet MetricPoint는 OpenMetrics 2.0의 StateSet Metric과 동등해요.
StateSet MetricGroup은 하나 이상의 상태를 포함하고 상태마다 불리언 값이 있는 Metric 하나를 포함해야(MUST) 해요. 상태에는 이름이 있으며 이것은 문자열이에요.
StateSet으로 인코딩되면 ENUM은 단일 타임스탬프에 대해 MetricGroup 내에서 정확히 하나의 1(true) 샘플을 가져야(MUST) 해요.
이것은 enum 값이 시간에 따라 변하고 상태 수가 몇 개보다 많지 않을 때 적합해요.
StateSet 타입의 MetricFamily는 빈 Unit 문자열을 가져야(MUST) 해요.
Info
Info 메트릭은 프로세스 수명 동안 변하지 않아야 하는 텍스트 정보를 노출하는 데 사용돼요. 흔한 예는 애플리케이션 버전, 리비전 관리 커밋, 컴파일러 버전이에요.
Info 메트릭의 MetricFamily 이름은 _info로 끝나야(MUST) 해요.
Info 타입의 MetricFamily는 빈 Unit 문자열을 가져야(MUST) 해요.
Histogram
히스토그램은 이산적 사건의 분포를 측정해요. 흔한 예는 HTTP 요청의 지연 시간, 함수 실행 시간, I/O 요청 크기예요.
Histogram 샘플은 Count와 Sum을 포함해야(MUST) 해요.
Count 값은 히스토그램이 측정한 측정 수와 같아야(MUST) 해요. Count는 의미상 카운터예요. Count는 정수여야(SHOULD) 해요. Count는 음수여서는 안(MUST NOT) 돼요. Count는 +Inf, NaN이어서는 안(SHOULD NOT) 돼요.
Float Count는 정수 범위를 넘을 수 있는 덧셈 같은 히스토그램에 대한 산술 연산의 결과를 노출할 수 있게 허용돼요.
Sum 값은 측정된 모든 이벤트 값의 합과 같아야(MUST) 해요. Sum은 히스토그램이 측정한 음수 이벤트 값이 없는 한에서만 의미상 카운터예요.
히스토그램은 클래식 버킷이나 네이티브 버킷 또는 둘 다에서 NaN이 아닌 값을 측정해야(MUST) 해요. NaN 측정은 클래식과 네이티브 버킷에서 서로 다르며, 각 섹션을 참조하세요.
모든 버킷은 잘 정의된 경계와 값을 가져야(MUST) 해요. 버킷 값을 흔히 버킷 카운트라고 해요. 버킷의 경계는 NaN이어서는 안(MUST NOT) 돼요. 버킷 값은 의미상 카운터예요. 버킷 값은 정수여야(SHOULD) 해요. 버킷 값은 음수여서는 안(MUST NOT) 돼요. 버킷 값은 +Inf, NaN이어서는 안(SHOULD NOT) 돼요.
Float 버킷 값은 정수 범위를 넘을 수 있는 히스토그램에 대한 산술 연산의 결과를 노출할 수 있게 허용돼요.
히스토그램은 NaN 측정을 포함해서는 안(SHOULD NOT) 돼요. Sum에 NaN을 포함하면 Sum이 NaN이 되어 시계열 수명 동안 실제 측정의 합을 가리기 때문이에요. 히스토그램이 NaN 측정을 포함하면 NaN 측정은 Count에 세어져야(MUST) 하고 Sum은 NaN이어야(MUST) 해요.
히스토그램이 +Inf 또는 -Inf 측정을 포함하면 +Inf 또는 -Inf는 Count에 세어져야(MUST) 하고 Sum에 더해져야(MUST) 하며, 잠재적으로 Sum이 +Inf, -Inf 또는 NaN이 될 수 있어요. 후자는 예를 들어 +Inf에 -Inf를 더하는 경우예요. 이 경우 유한 측정의 합은 히스토그램의 다음 리셋까지 가려진다는 점에 유의하세요.
Histogram 샘플은 시작 타임스탬프를 가져야(SHOULD) 해요.
Histogram 메트릭에 클래식 버킷이 있는 샘플이 있으면, Histogram의 Metric의 LabelSet은 "le" 레이블 이름을 가져서는 안(MUST NOT) 돼요. 샘플이 _bucket 접미사를 가진 클래식 histogram 시리즈로 저장된 경우, histogram의 "le" 레이블이 버킷 임계값에서 생성된 "le" 레이블과 충돌하기 때문이에요.
Histogram 타입은 시간에 따라 누적되지만 리셋될 수(MAY) 있어요. 히스토그램이 리셋되면 Sum, Count, 클래식 버킷, 네이티브 버킷은 0 상태로 리셋되어야(MUST) 하고, 시작 타임스탬프가 존재하면 대략적인 리셋 시간으로 설정되어야(MUST) 해요. 히스토그램 리셋은 히스토그램이 사용하는 네이티브 버킷 수를 제한하는 데 유용할 수 있어요.
Histogram 샘플은 exemplar를 가질 수(MAY) 있어요. 히스토그램 샘플의 exemplar 값은, 클래식 버킷이 포함되면 클래식 버킷마다 하나의 exemplar를 유지하는 것처럼, 고르게 분포되어야(SHOULD) 해요.
클래식 버킷 (Classic Buckets)
모든 클래식 버킷은 임계값을 가져야(MUST) 해요. 샘플 내에서 클래식 버킷 임계값은 고유해야(MUST) 해요. 클래식 버킷 임계값은 음수일 수(MAY) 있어요.
클래식 버킷은 그것보다 작거나 같은 측정 값 수를 세야(MUST) 해요. 낮은 버킷에도 세어지는 측정 값을 포함해요. 이는 모니터링 시스템이 성능 또는 anti-denial-of-service 이유로 +Inf 버킷 외의 어떤 버킷도 세분성을 잃지만 여전히 유효한 히스토그램인 방식으로 버릴 수 있게 해요.
예를 들어 클래식 버킷과 임계값 1, 2, 3, +Inf를 가진 초 단위 요청 지연 시간을 나타내는 메트릭의 경우, value_1 <= value_2 <= value_3 <= value_+Inf가 따른다. 10개의 요청이 각각 1초 걸렸다면 1, 2, 3, +Inf 버킷의 값은 모두 10과 같을 거예요.
클래식 버킷이 있는 히스토그램 샘플은 +Inf 임계값을 가진 클래식 버킷 하나를 가져야(MUST) 해요. +Inf 버킷은 모든 측정을 세요. Count 값은 +Inf 버킷의 값과 같아야(MUST) 해요.
노출된 클래식 버킷 임계값은 시간이 지나도, 그리고 집계되도록 의도된 타깃 간에도 일정하게 유지되어야(SHOULD) 해요. 임계값의 변경은 영향받는 히스토그램이 같은 연산(예: 서로 다른 메트릭의 집계나 시간에 따른 rate 계산)의 일부가 되는 것을 막을 수 있어요.
NaN 값이 허용되면 +Inf 버킷에 세어져야(MUST) 하고 다른 버킷에는 세어져서는 안(MUST NOT) 돼요. 이유는 NaN이 수학적으로 어떤 버킷에도 속하지 않지만, 계측 라이브러리는 전통적으로 그것을 +Inf 버킷에 넣기 때문이에요.
네이티브 버킷 (Native Buckets)
네이티브 버킷이 있는 히스토그램 샘플은 Schema 값을 가져야(MUST) 해요. Schema는 -4에서 8(포함) 사이의 8비트 서명 정수여야(MUST) 하며, 이를 표준(지수) 스키마라 해요.
-4에서 8 범위 밖의 Schema 값은 미래 사용을 위해 예약되며 사용해서는 안(MUST NOT) 돼요.
어떤 표준 스키마 n에 대해서도 히스토그램 샘플은 양수 및/또는 음수 네이티브 버킷을 포함할 수(MAY) 있고 제로 네이티브 버킷을 포함해야(MUST) 해요. 빈 양수 또는 음수 네이티브 버킷은 존재해서는 안(SHOULD NOT) 돼요.
표준 스키마의 경우 인덱스 i를 가진 양수 또는 음수 네이티브 버킷의 경계는 다음과 같이 계산되어야(MUST) 해요(Python 구문 사용):
양수 네이티브 버킷의 포함 상한: (2**2**-n)**i
양수 네이티브 버킷의 제외 하한: (2**2**-n)**(i-1)
음수 네이티브 버킷의 포함 하한: -((2**2**-n)**i)
음수 네이티브 버킷의 제외 상한: -((2**2**-n)**(i-1))
i는 음수가 될 수(MAY) 있는 정수예요.
float64로 표현 가능한 가장 크고 작은 유한 값(MaxFloat64, MinFloat64)과 양수·음수 무한대 값(+Inf, -Inf)에 관한 위 규칙의 예외가 있어요:
MaxFloat64를 포함하는 (위 경계 공식에 따른) 양수 네이티브 버킷은 (float64를 오버플로할 위 공식으로 계산된 한계 대신) MaxFloat64의 포함 상한을 가져요.
다음 양수 네이티브 버킷(이전 항목의 버킷에 상대적인 인덱스 i+1)은 MaxFloat64의 제외 하한과 +Inf의 포함 상한을 가져요. (양수 네이티브 오버플로 버킷이라고 부를 수 있어요.)
MinFloat64를 포함하는 (위 경계 공식에 따른) 음수 네이티브 버킷은 (float64를 언더플로할 위 공식으로 계산된 한계 대신) MinFloat64의 포함 하한을 가져요.
다음 음수 네이티브 버킷(이전 항목의 버킷에 상대적인 인덱스 i+1)은 MinFloat64의 제외 상한과 -Inf의 포함 하한을 가져요. (음수 네이티브 오버플로 버킷이라고 부를 수 있어요.)
위에서 설명한 +Inf와 -Inf 버킷 너머의 네이티브 버킷은 사용해서는 안(MUST NOT) 돼요.
제로 네이티브 버킷의 경계는 [-threshold, threshold]를 포함해요. 제로 임계값은 음수가 아닌 float64 값(threshold >= 0.0)이어야(MUST) 해요.
제로 임계값이 양수(threshold > 0)면, 제로 네이티브 버킷에 속하는 측정 값은 제로 네이티브 버킷에 세어져야(MUST) 하고 다른 네이티브 버킷에는 세어져서는 안(MUST NOT) 돼요. 제로 임계값은 임의 네이티브 버킷의 하한과 같아야(SHOULD) 해요.
NaN 값이 허용되지 않으면 Count 값은 음수, 양수, 제로 네이티브 버킷의 합과 같아야(MUST) 해요.
NaN 값이 허용되면 어떤 네이티브 버킷에도 세어져서는 안(MUST NOT) 되고 Count에 세어져야(MUST) 해요. Count와 음수·양수·제로 네이티브 버킷의 합의 차이는 NaN 관측치 수여야(MUST) 해요. 이유는 NaN이 수학적으로 어떤 버킷에도 속하지 않기 때문이에요.
GaugeHistogram
GaugeHistogram은 현재 분포를 측정해요. 흔한 예는 항목이 큐에서 얼마나 오래 기다렸는지, 큐의 요청 크기예요.
GaugeHistogram 샘플은 Gcount, Gsum 값을 포함해야(MUST) 해요.
Gcount 값은 GaugeHistogram에 현재 있는 측정 수와 같아야(MUST) 해요. Gcount는 의미상 게이지예요. Gcount는 정수여야(SHOULD) 해요. Gcount는 -Inf, +Inf, NaN, 음수여서는 안(SHOULD NOT) 돼요.
Float 및 음수 Gcount는 히스토그램의 시간에 따른 변화율 같은 GaugeHistogram에 대한 산술 연산의 결과를 노출할 수 있게 허용돼요.
Gsum 값은 GaugeHistogram에 현재 있는 모든 측정 값의 합과 같아야(MUST) 해요. Gsum은 의미상 게이지예요.
GaugeHistogram은 클래식 버킷이나 네이티브 버킷 또는 둘 다에서 NaN이 아닌 값을 측정해야(MUST) 해요. NaN 측정은 클래식과 네이티브 버킷에서 서로 다르며, 각 섹션을 참조하세요.
GaugeHistogram이 클래식 또는 네이티브 버킷 중 하나에서 값 측정을 멈추고 다른 쪽에서 계속 측정하면, 측정을 멈춘 버킷을 비우고 노출하지 않아야(MUST) 해요. 이는 두 종류의 버킷에서 서로 다른 분포를 동시에 노출하는 것을 피해요.
모든 버킷은 잘 정의된 경계와 값을 가져야(MUST) 해요. 버킷의 경계는 NaN이어서는 안(MUST NOT) 돼요. 버킷 값은 정수여야(SHOULD) 해요. 의미상 버킷 값은 게이지이며 -Inf, +Inf, NaN, 음수여서는 안(SHOULD NOT) 돼요.
Float 및 음수 버킷 값은 히스토그램의 시간에 따른 변화율 같은 GaugeHistogram에 대한 산술 연산의 결과를 노출할 수 있게 허용돼요.
GaugeHistogram은 NaN 측정을 포함해서는 안(SHOULD NOT) 돼요. GaugeHistogram이 NaN 측정을 포함하면 NaN 측정은 Gcount에 세어져야(MUST) 하고 Gsum은 NaN이어야(MUST) 해요.
GaugeHistogram이 +Inf 또는 -Inf 측정을 포함하면 +Inf 또는 -Inf는 Gcount에 세어져야(MUST) 하고 Gsum에 더해져야(MUST) 하며, 잠재적으로 Gsum이 +Inf, -Inf 또는 NaN이 될 수 있어요. 후자는 예를 들어 +Inf에 -Inf를 더하는 경우예요.
GaugeHistogram 메트릭에 클래식 버킷이 있는 샘플이 있으면, GaugeHistogram의 Metric의 LabelSet은 "le" 레이블 이름을 가져서는 안(MUST NOT) 돼요. 샘플이 _bucket 접미사를 가진 클래식 histogram 시리즈로 저장된 경우, GaugeHistogram의 "le" 레이블이 버킷 임계값에서 생성된 "le" 레이블과 충돌하기 때문이에요.
GaugeHistogram의 클래식과 네이티브 버킷은 Count와 Sum과 같은 역할을 하는 Gcount와 Gsum과 함께 Histogram과 같은 모든 규칙을 따라요.
GaugeHistogram의 exemplar는 Histogram과 같은 모든 규칙을 따라요.
Summary
Summary도 이산적 사건의 분포를 측정하며, 히스토그램이 너무 비싸고 소수의 미리 계산된 quantile로 충분할 때 사용할 수(MAY) 있어요.
Summary는 사용하지 않는 것이 좋아요(SHOULD NOT). quantile은 집계할 수 없고 사용자가 그것이 다루는 기간을 종종 추론할 수 없기 때문이에요. 일부 기존 계측 라이브러리가 미리 계산된 quantile을 노출하고 히스토그램을 지원하지 않으므로 역호환성을 위해 사용될 수(MAY) 있어요.
Summary 샘플은 Count, Sum, quantile 세트를 포함해야(MUST) 해요.
의미상 Count와 Sum 값은 카운터이므로 NaN이거나 음수여서는 안(MUST NOT) 돼요. Count는 정수여야(MUST) 해요.
Summary는 시작 타임스탬프를 가져야(SHOULD) 해요.
시작 타임스탬프는 quantile 값의 수집 기간에 기반해서는 안(MUST NOT) 돼요.
Quantile은 quantile에서 값으로의 맵이에요. 예는 myapp_http_request_duration_seconds라는 메트릭에서 값 0.2를 가진 quantile 0.95로, 알 수 없는 기간에 걸쳐 95번째 백분위수 지연 시간이 200ms라는 뜻이에요. 관련 기간에 이벤트가 없으면 quantile 값은 NaN이어야(MUST) 해요. Quantile의 Metric의 LabelSet은 "quantile" 레이블 이름을 가져서는 안(MUST NOT) 돼요. Quantile은 0과 1 사이(포함)여야(MUST) 해요. Quantile 값은 음수여서는 안(MUST NOT) 돼요. Quantile 값은 최근 값을 나타내야(SHOULD) 해요. 일반적으로 지난 5-10분에 걸친 값이에요.
Unknown
Unknown은 사용하면 안(SHOULD NOT) 돼요. 제3자 시스템에서 개별 메트릭의 타입을 결정하는 것이 불가능할 때 사용할 수(MAY) 있어요.
Unknown 타입의 메트릭에 있는 샘플은 Number 또는 CompositeValue 값을 가져야(MUST) 해요.
텍스트 형식 (Text Format)
OpenMetrics 형식은 Regular Chomsky Grammars라서 빠르고 작은 파서를 작성할 수 있어요.
부분적이거나 유효하지 않은 exposition은 전체적으로 오류로 간주해야(MUST) 해요.
참고: 이전 버전의 OpenMetrics는 OpenMetric protobuf 형식을 지정하곤 했어요. OpenMetrics 2.0은 protobuf 표현을 포함하지 않아요. 공식 Prometheus protobuf wire format을 포함한 사용 가능한 형식에 대해서는 exposition formats 문서를 참조하세요.
프로토콜 협상
모든 수집기 구현은 TLS 1.2 이상으로 보호된 데이터를 수집할 수 있어야(MUST) 하고 TLS 1.3 이상을 지원해야(SHOULD) 해요. 모든 exposer는 TLS 1.3 이상으로 보호된 데이터를 내보낼 수 있어야(SHOULD) 해요. 수집기 구현은 TLS 없는 HTTP에서 데이터를 수집할 수 있어야(SHOULD) 해요. 모든 구현은 데이터 전송에 TLS를 사용해야(SHOULD) 해요.
사용할 OpenMetrics 형식 버전의 협상은 대역외(out-of-band)예요. 예를 들어 HTTP를 통한 풀 기반 exposition의 경우 표준 HTTP 콘텐츠 타입 협상이 사용되며, 더 새로운 버전이 요청되지 않으면 표준의 가장 오래된 버전(즉 1.0.0)으로 기본 설정되어야(MUST) 해요.
푸시 기반 협상은 본질적으로 더 복잡해요. exposer가 일반적으로 연결을 시작하기 때문이에요. 생산자는 수집기가 달리 요청하지 않는 한 표준의 가장 오래된 버전(즉 1.0.0)을 사용해야(MUST) 해요.
ABNF
ABNF는 RFC 7405에 따름
RFC 7405는 RFC 5234 위에 구축되지만 문자열 리터럴에 명시적 대소문자 구분 표기법을 추가해요. 리터럴 %s"text"는 text가 대소문자 구분이고, %i"text"는 대소문자 비구분을 의미해요.
"exposition"은 ABNF의 최상위 토큰이에요.
exposition = metricset HASH SP %s"EOF" [ LF ]
metricset = *metricfamily
metricfamily = *metric-descriptor *sample
metric-descriptor = HASH SP %s"TYPE" SP (metricname / metricname-utf8) SP metric-type LF
metric-descriptor =/ HASH SP %s"HELP" SP (metricname / metricname-utf8) SP escaped-string LF
metric-descriptor =/ HASH SP %s"UNIT" SP (metricname / metricname-utf8) SP *metricname-char LF
metric-type = %s"counter" / %s"gauge" / %s"histogram" / %s"gaugehistogram" / %s"stateset"
metric-type =/ %s"info" / %s"summary" / %s"unknown"
sample = metricname-and-labels SP value [SP timestamp] [SP start-timestamp] *exemplar LF
value = number / "{" composite-value "}"
timestamp = realnumber
; Lowercase st @ timestamp
start-timestamp = %s"st" "@" timestamp
exemplar = SP HASH SP labels-in-braces SP number SP timestamp
metricname-and-labels = metricname [labels-in-braces] / name-and-labels-in-braces
labels-in-braces = "{" [label *(COMMA label)] "}"
name-and-labels-in-braces = "{" metricname-utf8 *(COMMA label) "}"
label = label-key "=" DQUOTE escaped-string DQUOTE
; Number value
number = realnumber
; Case insensitive
number =/ [SIGN] (%i"inf" / %i"infinity")
number =/ %i"nan"
; Real floats
; Leading 0s explicitly okay
realnumber = [SIGN] 1*DIGIT ["." *DIGIT] [ "e" [SIGN] 1*DIGIT ]
realnumber =/ [SIGN] *DIGIT "." 1*DIGIT [ "e" [SIGN] 1*DIGIT ]
; Integers
; Leading 0s explicitly okay
integer = [SIGN] 1*"0" / [SIGN] positive-integer
non-negative-integer = ["+"] 1*"0" / ["+"] positive-integer
positive-integer = *"0" positive-digit *DIGIT
positive-digit = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
BS = "\"
COMMA = ","
HASH = "#"
SIGN = "-" / "+"
metricname = metricname-initial-char 0*metricname-char
metricname-char = metricname-initial-char / DIGIT
metricname-initial-char = ALPHA / "_" / ":"
metricname-utf8 = DQUOTE escaped-string-non-empty DQUOTE
label-key = label-name / DQUOTE escaped-string-non-empty DQUOTE
label-name = label-name-initial-char *label-name-char
label-name-char = label-name-initial-char / DIGIT
label-name-initial-char = ALPHA / "_"
escaped-string = *escaped-char
escaped-string-non-empty = 1*escaped-char
escaped-char = normal-char
escaped-char =/ BS ("n" / DQUOTE / BS)
escaped-char =/ BS normal-char
; Any unicode character, except newline, double quote, and backslash
normal-char = %x00-09 / %x0B-21 / %x23-5B / %x5D-D7FF / %xE000-10FFFF
; Composite values
composite-value = histogram-value / gauge-histogram-value / summary-value
; Histograms
histogram-value = h-count "," h-sum "," histogram-buckets
gauge-histogram-value = %s"g" h-count "," %s"g" h-sum "," histogram-buckets
; count:x
h-count = %s"count" ":" number
; sum:f allows real numbers and +-Inf and NaN
h-sum = %s"sum" ":" number
histogram-buckets = classic-buckets / native-buckets [ "," classic-buckets ]
; bucket:[...,+Inf:v] The +Inf bucket is required.
classic-buckets = %s"bucket" ":" "[" [ ch-le-counts "," ] ch-pos-inf-bucket "]"
ch-le-counts = (ch-neg-inf-bucket / ch-le-bucket) *("," ch-le-bucket)
ch-pos-inf-bucket = "+" %s"Inf" ":" number
ch-neg-inf-bucket = "-" %s"Inf" ":" number
ch-le-bucket = realnumber ":" number
; schema:3,zero_threshold:1e-128,zero_count:2,negative_spans:[1:1],negative_buckets:[2],positive_spanes:[-3:1,2:2],positive_buckets:[3,1,0]
native-buckets = nh-schema "," nh-zero-threshold "," nh-zero-count [ "," nh-negative-spans "," nh-negative-buckets ] [ "," nh-positive-spans "," nh-positive-buckets ]
; schema:i
nh-schema = %s"schema" ":" integer
; zero_threshold:f
nh-zero-threshold = %s"zero_threshold" ":" realnumber
; zero_count:x
nh-zero-count = %s"zero_count" ":" number
; negative_spans:[1:2,3:4] and positive_spans:[-3:1,2:2]
nh-negative-spans = %s"negative_spans" ":" "[" [nh-spans] "]"
nh-positive-spans = %s"positive_spans" ":" "[" [nh-spans] "]"
; Spans hold offset and length. The offset can start from any index, even
; negative, however subsequent spans can only advance the index, not decrease it.
nh-spans = nh-start-span *("," nh-span)
nh-start-span = integer ":" non-negative-integer
nh-span = non-negative-integer ":" non-negative-integer
; negative_buckets:[1,2,3] and positive_buckets:[1,2,3]
nh-negative-buckets = %s"negative_buckets" ":" "[" [nh-buckets] "]"
nh-positive-buckets = %s"positive_buckets" ":" "[" [nh-buckets] "]"
nh-buckets = number *("," number)
; Summary
; count:12.0,sum:100.0,quantile:[0.9:2.0,0.95:3.0,0.99:20.0]
summary-value = cs-count "," cs-sum "," cs-quantile
; count:x where x is a number
cs-count = %s"count" ":" number
; sum:x where x is a real number or +-Inf or NaN
cs-sum = %s"sum" ":" number
; quantile:[...]
cs-quantile = %s"quantile" ":" "[" [ cs-q-counts ] "]"
cs-q-counts = cs-q-count *("," cs-q-count)
cs-q-count = realnumber ":" number
전체 구조
UTF-8을 사용해야(MUST) 해요. 바이트 순서 표시(BOM)는 사용해서는 안(MUST NOT) 돼요. NULL(바이트 0x00)은 유효한 UTF-8 바이트이지만 예를 들어 바이트 0xFF는 그렇지 않다는 점에 유의하세요.
콘텐츠 타입은 다음과 같아야(MUST) 해요:
application/openmetrics-text; version=2.0.0; charset=utf-8
줄 끝은 줄 바꿈(\n)으로 신호되어야(MUST) 하고 캐리지 리턴(\r)을 포함해서는 안(MUST NOT) 돼요. Exposition은 EOF로 끝나야(MUST) 하고 EOF\n으로 끝나야(SHOULD) 해요.
완전한 exposition의 예:
# TYPE acme_http_router_request_seconds summary
# UNIT acme_http_router_request_seconds seconds
# HELP acme_http_router_request_seconds Latency though all of ACME's HTTP request router.
acme_http_router_request_seconds{path="/api/v1",method="GET"} {count:807283,sum:9036.32,quantile:[0.95:2,0.99:20]} [email protected]
acme_http_router_request_seconds{path="/api/v2",method="GET"} {count:34,sum:479.3,quantile:[0.95:2.5,0.99:2.9]} [email protected]
# TYPE go_goroutines gauge
# HELP go_goroutines Number of goroutines that currently exist.
go_goroutines 69
# TYPE process_cpu_seconds_total counter
# UNIT process_cpu_seconds_total seconds
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
process_cpu_seconds_total 4.20072246e+06
# TYPE acme_http_request_seconds histogram
# UNIT acme_http_request_seconds seconds
# HELP acme_http_request_seconds Latency histogram of all of ACME's HTTP requests.
acme_http_request_seconds{path="/api/v1",method="GET"} {count:2,sum:1.2e2,schema:0,zero_threshold:1e-4,zero_count:0,positive_spans:[1:2],positive_buckets:[1,1],bucket:[0.5:1,1:2,+Inf:2]} [email protected]
# TYPE acme_http_request_seconds:rate5m gaugehistogram
acme_http_request_seconds:rate5m{path="/api/v1",method="GET"} {gcount:0.01,gsum:2.0,schema:0,zero_threshold:1e-4,zero_count:0.0,positive_spans:[1:2],positive_buckets:[0.005,0.005]}
# TYPE "foodb.read.errors" counter
# HELP "foodb.read.errors" The number of errors in the read path for fooDb.
{"foodb.read.errors","service.name"="my_service"} 3482
# EOF
UTF-8 인용
metricname의 ABNF 정의를 따르지 않는 메트릭 이름은 이중 따옴표로 묶어야 하고 대체 UTF-8 구문을 사용해야 해요. 그런 메트릭에서 인용된 메트릭 이름은 ABNF에 따라 레이블 이름과 등호 없이 첫 번째 항목으로 괄호 안으로 옮겨져야 해요. 메트릭 이름은 TYPE, UNIT, HELP 라인에서 이중 따옴표로 묶여야 해요. 인용과 대체 메트릭 구문은 이름이 인용을 요구하는지 여부와 무관하게 모든 메트릭 이름에 사용될 수(MAY) 있어요.
label-name ABNF 정의를 따르지 않는 레이블 이름은 이중 따옴표로 묶어야 해요. 어떤 레이블 이름도 이중 따옴표로 묶을 수(MAY) 있어요.
정규식으로 표현하면 인용할 필요가 없는 메트릭 이름은 ^[a-zA-Z_:][a-zA-Z0-9_:]*$와 일치한다. 레이블 이름은 ^[a-zA-Z_][a-zA-Z0-9_]*$와 일치한다.
완전한 예:
# TYPE "process.cpu.seconds" counter
# UNIT "process.cpu.seconds" seconds
# HELP "process.cpu.seconds" Total user and system CPU time spent in seconds.
{"process.cpu.seconds","node.name"="my_node"} 4.20072246e+06
# TYPE "quoting_example" gauge
# HELP "quoting_example" Number of goroutines that currently exist.
{"quoting_example","foo"="bar"} 4.5
# EOF
이스케이프
ABNF가 이스케이프를 언급하는 곳에서 다음 이스케이프를 적용해야(MUST) 해요:
- 줄 바꿈,
\n(0x0A) -> 문자 그대로\n(바이트코드 0x5c 0x6e) - 이중 따옴표 ->
\"(바이트코드 0x5c 0x22) - 백슬래시 ->
\\(바이트코드 0x5c 0x5c)
이중 백슬래시는 백슬래시 문자를 나타내는 데 사용해야(SHOULD) 해요. 정의되지 않은 이스케이프 시퀀스에는 단일 백슬래시를 사용해서는 안(SHOULD NOT) 돼요. 예를 들어 \\a는 \a와 동등하며 선호돼요.
이스케이프는 인용된 UTF-8 문자열에도 적용해야(MUST) 해요.
숫자
정수는 소수점을 가져서는 안(MUST NOT) 돼요. 예는 23, 0042, 1341298465647914예요.
부동 소수점 숫자는 소수점이나 과학적 표기법으로 표현해야(MUST) 해요. 예는 8903.123421과 1.89e-7이에요. 부동 소수점 숫자는 IEEE 754가 정의하는 64비트 부동 소수점 값 범위 안에 맞아야(MUST) 하지만, 정밀도 손실을 초래하는 가수부 비트가 너무 많을 수(MAY) 있어요. 이는 나노초 해상도 타임스탬프를 인코딩하는 데 사용될 수(MAY) 있어요.
CompositeValue
CompositeValue는 필드가 있는 구조화된 데이터로 표현돼요. 필드 주변에 공백이 있어서는 안(MUST NOT) 돼요. 형식과 가능한 값의 정확한 세부 사항은 ABNF를 참조하세요.
타임스탬프
나노초 정밀도가 필요하면 타임스탬프에 지수 float 렌더링을 사용해서는 안(SHOULD NOT) 돼요. float64의 렌더링은 충분한 정밀도가 없기 때문이에요. 예: 1604676851.123456789.
Exemplar
레이블이 없는 Exemplar는 빈 LabelSet을 {}로 나타내야(MUST) 해요.
MetricFamily
MetricFamily 사이에 명시적 구분자가 있어서는 안(MUST NOT) 돼요. 다음 MetricFamily는 메타데이터나 새 MetricFamily의 새 Metric 이름으로 신호되어야(MUST) 해요.
MetricFamily는 인터리브되어서는 안(MUST NOT) 돼요.
같은 MetricFamily의 이름과 Metric의 이름은 같은 인용을 가져야(SHOULD) 해요.
이를 위반하는 예:
# TYPE "read_errors" counter
# HELP read_errors The number of errors in the read path for fooDb.
{"read_errors","service.name"="my_service"} 3482
read_errors{"service.name"="my_service2"} 123
MetricFamily 메타데이터
네 가지 메타데이터가 있어요: MetricFamily 이름, TYPE, UNIT, HELP. foo_total이라는 Counter 메트릭의 메타데이터 예:
# TYPE foo_total counter
TYPE이 노출되지 않으면 MetricFamily는 Unknown 타입으로 해석되어야(MUST) 해요.
단위가 지정되면 UNIT 메타데이터 라인에 제공되어야(MUST) 해요. 추가로 밑줄과 단위가 MetricFamily 이름의 접미사(또는 Counter의 경우 _total 앞의 접요사 infix)여야(SHOULD) 해요.
단위가 MetricFamily 이름의 접미사(또는 접요사)가 아닌 메트릭을 최종 사용자에게 직접 노출하면 메트릭의 단위가 무엇인지 혼동이 생겨 사용성이 떨어질 수 있다는 점을 유의하세요.
"seconds" 단위를 가진 foo_seconds_total 메트릭의 유효한 예:
# TYPE foo_seconds_total counter
# UNIT foo_seconds_total seconds
단위가 이름의 접미사나 접요사가 아닌, 유효하지만 권장되지 않는 예:
# TYPE foo_total counter
# UNIT foo_total seconds
다음을 갖는 것도 유효해요:
# TYPE foo_seconds_total counter
단위가 알려져 있으면 제공해야(SHOULD) 해요.
UNIT이나 HELP 메타데이터 라인은 새 줄 앞에 빈 값 문자열을 가질 수(MAY) 있어요. 이것은 메타데이터 라인이 없는 것처럼 취급해야(MUST) 해요.
전체 예:
# TYPE foo_seconds_total counter
# UNIT foo_seconds_total seconds
# HELP foo_seconds_total Some text and \n some \" escaping
메트릭 이름을 이중 따옴표로 묶어야 하는 경우는 UTF-8 인용 섹션을 참조하세요.
MetricFamily에 대해 각 유형의 메타데이터 라인이 둘 이상 있어서는 안(MUST NOT) 돼요. 순서는 TYPE, UNIT, HELP여야(SHOULD) 해요.
이 메타데이터와 메시지 끝의 EOF 라인 외에는 #으로 시작하는 라인을 노출해서는 안(MUST NOT) 돼요.
알 수 없는 메타데이터
수집기는 메타데이터 라인이 없는 Metric Family를 지원해야(MUST) 해요.
[이어지는 이후 섹션들: Text format의 Metric/Sample 표현, Failure modes(실패 모드), Design considerations(설계 고려사항: 범위, 무상태성, 단위와 기본 단위, 메트릭 이름 짓기, 타임스탬프 노출, 크기 제한, 보안, IANA 등)는 OpenMetrics 1.0과 동일한 원칙을 따르면서 CompositeValue와 네이티브/클래식 버킷을 지원하도록 변경되었습니다. 이 문서는 출처 본문의 전 섹션 구조를 그대로 번역한 것입니다.]
더 알아보기 (Learn more)
- OpenMetrics 1.0 사양 — 이전 안정 버전 사양
- 네이티브 히스토그램 — 합성 값의 근간이 되는 네이티브 히스토그램
- Prometheus exposition 형식 — 다양하게 지원되는 exposition 형식
- OpenMetrics 저장소 — 사양 원본과 이슈/피드백
- OpenTelemetry — 호환성을 목표로 하는 OTel 데이터 모델