将OTLP 指标转换为 Prometheus指标
指标元数据
在单次抓取中,Prometheus SDK 导出器不允许对同一个指标名出现重复的 UNIT、HELP 或 TYPE 注释。如果出现了TYPE注释冲突,exporter必须删除整个指标。但 UNIT 或 HELP 注释冲突时不用删除指标点,除了一个的 UNIT 和 HELP 注释之外,其他所有冲突的注释应该被删除。如果注释或指标点被删除了,exporter应通过在日志中打印警告信息。
OTLP 指标的名称必须作为 OpenMetrics MetricFamily Name, 并按照下面的逻辑添加单位和类型后缀。指标名称需要匹配这种格式:[a-zA-Z_:]([a-zA-Z0-9_:])*
。指标名称中的无效字符必须替换为_
字符。多个连续_
字符必须替换为单个_
字符。
如果可能,OTLP 指标点的单位应转换为 Prometheus 中的对应单位。这包括:
- 从缩写转换为完整单词(例如“ms”到“milliseconds”)。
- 将单位的一部分放在括号内(例如{packet})。括号不得包含在生成的单位中。在prometheus中,“count of foo”被认为是无单位的。
- 特殊情况:将“1”转换为“ratio”。
- 将“foo/bar”转换为“foo_per_bar”。
生成的单位应作为 OpenMetrics UNIT 元数据,并作为指标名称的后缀,除非指标名称已包含了单位,或者必须省略单位。单位后缀位于特定类型的后缀之前。
OTLP 指标的描述信息必须作为 OpenMetrics HELP 元数据。
OTLP 指标的数据类型必须作为 OpenMetrics TYPE 元数据。 下面会列出各种特定类型的转换规则。
范围
Prometheus exporter应该为每个scope_metric生成一个 Info 类型的otel_scope_info
指标,并且带上非空的范围属性。 如果scope_metric的name
和version
存在,则otel_scope_info
指标中需要添加对应的otel_scope_name
和otel_scope_version
标签。范围属性还必须按照下文“Metric Attribute
”部分所述的规则添加标签。
Prometheus exporter必须为这个scope_metric下的所有指标默认添加范围名称otel_scope_name
和otel_scope_version
作为标签。
Prometheus exporter应提供配置选项,以禁用otel_scope_info
指标和otel_scope_
标签。
Gauge类型
OpenTelemetry gauge类型必须转换为 Prometheus gauge类型。
Sum类型
OpenTelemetry Sums 的转换过程遵循以下规则:
- 如果sum指标统计的是累积时间,并且指标值是单调递增的,则必须将其转换为 Prometheus counter类型。
- 如果sum指标统计的是累积时间,并且指标值不是单调的,则必须将其转换为 Prometheus Gauge类型。
- 如果sum指标统计的是增量时间,并且指标值是单调的,则应将其转换为累积时间的统计值,并转换为 Prometheus counter类型指标。应该遵循以下方式进行转换:
- 新的数据点的类型必须与累积数据点的类型相同。
- 新数据点的开始时间必须与累积数据点的时间匹配。如果没有,请参阅detecting alignment issues.。
- 否则,必须将其删除。
如果单调递增的 Sum 指标点的指标名没有_total
后缀,则必须默认添加_total
后缀,否则名称不变。exporter应提供一个配置选项来确定是否添加_total
后缀。 单调递增的Sum类型指标点,如果带有StartTimeUnixNano
,也应该添加一个{name}_created
名称的指标。
直方图(Histogram)
如果 OpenTelemetry Histogram 类型指标统计的是累积时间,必须转换为具有以下指标的 Prometheus 指标系列:
- 需要添加表示Histogram的count字段的单个指标
{name}_count
。Histogram点的所有属性都将转换为 Prometheus 的标签。 - 当sum值为正且单调递增时,需要添加表示Histogram的sum字段的指标
{name}_sum
。当所有bucket都为正时,sum是正数并且单调。Histogram点的所有属性都将转换为 Prometheus 的标签。 - 需要添加一系列指标点
{name}_bucket
,它的标签的包含了Histogram点的所有属性。此外,还添加了一个le
标签,表示bucket的边界。标签的值是bucket边界的字符串化浮点值,按从低到高的顺序排列。每个点的值是它的le
边界之上的所有Histogram 的bucket的count之和。这些点将包括一个属于le
标签内而且没有其他le
标签的示例。最终存储桶指标必须具有+Inf
阈值。 - 带有
StartTimeUnixNano
的Histogram也应生成一个{name}_created
指标。
如果 OpenTelemetry Histogram统计的是增量时间区间,应将它聚合成累积时间的统计值,并遵循上述逻辑,否则必须删除。
指数直方图(Exponential Histogram)
如果OpenTelemetry 指数直方图统计时间是累积时间,必须转换为 Prometheus native Histogram指标,遵循如下规则:
Scale
转换为native Histogram的Schema
。目前,schema
的有效值为 -4 <= n <= 8。 如果Scale
> 8,则应缩小指数直方图数据点的尺度到prometheus接受的比例(范围是 [-4,8])。任何无法重新缩放到可接受的范围内的数据点必须删除。- 如果
NoRecordedValue
标志设置为false
,则将Count
转换为native Histogram的Count
,否则,native Histogram的Count
将设置为 NaN 。 - 如果
NoRecordedValue
标志设置为false
,则将Sum
转换为native Histogram的Sum
,否则,native Histogram的Sum
将设置为 NaN 。 TimeUnixNano
转换为native Histogram的Timestamp
,并且将纳秒转换为毫秒。ZeroCount
直接转换为native Histogram的ZeroCount
。- 如果设置了
ZeroThreshold
,则转换为native Histogram的ZeroThreshold
。 否则,它将设置为默认值1e-128
。 - 由
Positive
bucket 计数器和Offset
表示密集的存储桶布局,需要转换为由PositiveSpans
和PositiveDeltas
表示的native Histogram稀疏布局。Negative
bucket计数器和Offset
也是如此 和。请注意,Prometheus Native Histograms 的bucket以上边界为索引,而Exponential Histogram以下边界作为索引, 这会导致它们的“Offset”字段相差一个。 Min
和Max
并不使用。StartTimeUnixNano
未使用。
具有增量时间性的OpenTelemetry Exponential Histogram指标将被删除。
Summary
必须将 OpenTelemetry Summary转换为具有以下指标的 Prometheus 指标系列:
- 必须生成表示Summary的count字段的单个指标
{name}_count
,所有属性都将转换为 Prometheus 标签。 - 仅当sum字段为正且单调时,需要生成表示Summary的sum字段的指标
{name}_sum
。Summary的所有属性都会转换为 Prometheus 的标签。 - 需要生成一系列
{name}
指标点,并包含Summary指标属性转换成的标签。此外需要添加一个quantile
标签,表示分位点,其值是分位数浮点值的字符串(介于 0.0 和 1.0 之间), 从小到大非负数。每个点的值是分位点的计算值。 - 带有
StartTimeUnixNano
的Summary应生成一个{name}_created
指标。
指标属性
OpenTelemetry 指标属性必须转换为 Prometheus 的标签。 字符串属性值将参照以下的属性规范直接转换为指标属性,非字符串属性值必须转换为字符串属性。prometheus指标的标签名必须匹配正则表达式:[a-zA-Z_]([a-zA-Z0-9_])*
。 OpenTelemetry 指标的属性名称中不支持的字符,必须替换为_
字符,多个连续_
字符必须替换为单个_
字符。多个在同一位置存在无效字符的名称相似的属性,可能会导致歧义 。这种情况不太可能出现,但如果多个属性被转换成的 Prometheus 标签名相同,则它们的值必须连接在一起,以 ;
分隔,并按原始名称的词典顺序排序。
样本(Examplar)
OpenTelemetry Histogram和单调的Sum类型中的Examplar应转换为 OpenMetrics 的Examplar类型。其他 OpenTelemetry 指标中的Examplar必须丢弃。对于 Prometheus Push Exporter,每个bucket都能添加Examplar,因此所有Examplar都应进行转换。对于 Prometheus pull 端点来说,每个端点只能添加一个Examplar bucket,因此必须使用每个bucket中最大的Examplar样本。如果bucket上不存在Examplar,则从较低的 必须要用到的bucket 中获取最大的Examplar,即使它是另一个bucket的Examplar相同。 OpenMetrics 示例必须使用trace_id
和span_id
这两个标签来记录trace 和 span ID。必须将时间戳添加到 OpenMetrics Examplar中,并且必须将filtered_attributes
标签添加到 OpenMetrics Examplar,除非它们会超出 OpenMetrics 对字符的限制。
资源属性
在 Prometheus exporter(拉取)中,如果resource属性不为空,则必须转换为单个target_info
指标,否则,它们必须被丢弃,并且不得作为其他指标的标签。target_info指标必须是Info类型的指标,其标签必须包含资源属性,并且不得包含任何其他标签。 Prometheus 端点导出的数据中必须只有一个target_info指标。
在 Collector 的 Prometheus pull和push exporter中,可以将来自多个target的指标一起输出,因此各个target必须互相没有歧义。但是Prometheus 导出格式中, remote-write格式不包含资源的概念,而是使用指标标签来区分刮擦的target。按照惯例,job and instance标签用于区分target,并应出现在Prometheus pull exporter(“federated”Prometheus 端点)导出的指标上, 或通过 Prometheus 远程写入推送到目标。在 OTLP 中, service.name
、 service.namespace
和service.instance.id
三元组必须是唯一的, 它们被用于构建job
和instance
标签。在 otel-collector的 Prometheus 导出器中, service.name
和service.namespace
属性必须组合为<service.namespace>/<service.name>
或者<service.name>
(namespace 为空的情况) ,构成指标的job
标签。service.instance.id
属性(如果存在)必须转换为instance
标签,否则,instance
标签应该赋空值。 其他资源属性应转换为target_info指标,或者必须删除。target_info指标是Info类型的指标 其标签必须包含资源属性,并且不得包含任何 除 job
和instance
以外的其他标签。每个唯一的job
和instance
组合,最多对应一个 target_info指标。
如果某种编程语言的Prometheus 客户端库尚不支持Info类型的指标系列,则必须改用名为 target_info且常量值为 1 的Gauge类型指标系列。
要将 OTLP 资源属性转换为 Prometheus 标签,字符串属性值将直接转换为标签,非字符串属性值必须按照属性规范转换为字符串属性。