Metrics API
Status: Stable, 除非另有说明
概述
Metrics API 由以下主要组件构成
- MeterProvider 是 API 的入口点。它提供对
Meter的访问。 - Meter 负责创建
Instrument。 - Instrument 负责报告 Measurements。
以下是使用 Metrics API 注入的进程内部对象层次结构的示例
+-- MeterProvider(default)
|
+-- Meter(name='io.opentelemetry.runtime', version='1.0.0')
| |
| +-- Instrument<Asynchronous Gauge, int>(name='cpython.gc', attributes=['generation'], unit='kB')
| |
| +-- instruments...
|
+-- Meter(name='io.opentelemetry.contrib.mongodb.client', version='2.3.0')
|
+-- Instrument<Counter, int>(name='client.exception', attributes=['type'], unit='1')
|
+-- Instrument<Histogram, double>(name='client.duration', attributes=['server.address', 'server.port'], unit='ms')
|
+-- instruments...
+-- MeterProvider(custom)
|
+-- Meter(name='bank.payment', version='23.3.5')
|
+-- instruments...
MeterProvider
可以使用 MeterProvider 访问 Meter。
通常,期望 MeterProvider 从一个中心位置访问。因此,API 应当提供一种方式来设置/注册和访问全局默认的 MeterProvider。
MeterProvider 操作
MeterProvider 必须提供以下功能
- 获取
Meter
获取 Meter
此 API 必须接受以下参数
name:指定 instrumentation scope 的名称,例如 instrumentation library(例如io.opentelemetry.contrib.mongodb)、包、模块或类名。如果应用程序或库内置了 OpenTelemetry instrumentation,那么 Instrumented library 和 Instrumentation library 可以指向同一个库。在这种情况下,name指的是该库或应用程序内的模块名称或组件名称。version:指定 instrumentation scope 的版本(如果 scope 有版本),例如库版本。示例值:1.0.0。用户可以提供
version,但这取决于他们的判断。因此,此 API 需要设计成可以接受version,但绝不能强制用户提供。[since 1.4.0]
schema_url:指定在发出的遥测数据中应记录的 Schema URL。用户可以提供
schema_url,但这取决于他们的判断。因此,此 API 需要设计成可以接受schema_url,但绝不能强制用户提供。[since 1.13.0]
attributes:指定要与发出的遥测数据关联的 instrumentation scope 属性。用户可以提供属性与 instrumentation scope 关联,但这取决于他们的判断。因此,此 API 必须设计成可以接受可变数量的属性,包括零个。
术语相同用于描述 Meter 的实例,当所有参数都相等时。术语不同用于描述 Meter 的实例,当至少有一个参数的值不同时。
Meter
Meter 负责创建 Instruments。
注意:Meter 不应负责配置。这应该是 MeterProvider 的责任。
Meter 操作
Meter 必须提供用于创建新 Instruments 的函数
- 创建新的 Counter
- 创建新的异步 Counter
- 创建新的 Histogram
- 创建新的 Gauge
- 创建新的异步 Gauge
- 创建新的 UpDownCounter
- 创建新的异步 UpDownCounter
有关 Instrument 创建的更多信息,请参阅下面的相应部分。
Instrument
Instruments 用于报告 Measurements。每个 Instrument 都将具有以下参数
- Instrument 的
name - Instrument 的
kind- 它是 Counter 还是其他类型,是同步的还是异步的 - 可选的
unit(度量单位) - 可选的
description - 可选的
advisory参数(混合)
Instruments 在创建时与 Meter 关联。Instruments 由 name、kind、unit 和 description 标识。
应考虑将诸如整数和浮点数之间的区别等语言级特性作为标识。
术语相同用于描述 Instrument 的实例,当所有标识字段都相等时。
通用特性
Instrument 名称语法
Instrument 名称语法使用 Augmented Backus-Naur Form 定义如下
instrument-name = ALPHA 0*254 ("_" / "." / "-" / "/" / ALPHA / DIGIT)
ALPHA = %x41-5A / %x61-7A; A-Z / a-z
DIGIT = %x30-39 ; 0-9
- 它们不是 null 或空字符串。
- 它们是区分大小写的 ASCII 字符串。
- 第一个字符必须是字母字符。
- 后续字符必须属于字母数字字符、‘_’、‘.’、‘-’ 和 ‘/’。
- 它们的最大长度可以为 255 个字符。
Instrument 单位
unit 是 Instrument 作者提供的可选字符串。API 应将其视为不透明字符串。
- 它必须是区分大小写的(例如,
kb和kB是不同的单位)、ASCII 字符串。 - 它的最大长度可以是 63 个字符。选择 63 这个数字是为了允许单位字符串(包括某些语言运行时上的
\0终止符)在性能至关重要时作为固定大小的数组/结构存储和比较。
Instrument 描述
description 是 Instrument 作者提供的可选自由格式文本。API 必须将其视为不透明字符串。
- 它必须支持 BMP(Unicode Plane 0),这基本上只是 UTF-8 的前三个字节(或
utf8mb3)。OpenTelemetry API 作者可以自行决定是否支持更多的 Unicode Planes。 - 它必须至少支持 1023 个字符。OpenTelemetry API 作者可以自行决定是否支持更多。
Instrument 建议参数
状态: 混合
advisory 参数是 Instrument 作者提供的一组可选建议,旨在帮助实现以最少的配置提供有用的输出。它们与其他参数的区别在于,实现可以忽略 advisory 参数。
OpenTelemetry SDK 必须按照此处的描述处理 advisory 参数。
advisory 参数可以是通用的,也可以仅适用于特定 Instrument kind。
Instrument 建议参数: ExplicitBucketBoundaries
状态: 稳定
适用于 Histogram instrument 类型。
ExplicitBucketBoundaries (double[]) 是聚合到 explicit bucket Histogram metric data point 时使用的建议存储桶边界集。
Instrument 建议参数: Attributes
状态: 开发中
适用于所有 instrument 类型。
Attributes(属性键列表)是用于结果 metric 的建议属性键集。
同步和异步 Instrument
Instrument 按是否为同步或异步进行分类
同步 Instrument(例如 Counter)旨在与应用程序/业务处理逻辑内联调用。例如,HTTP 客户端可以使用 Counter 来记录接收到的字节数。Measurements 由同步 Instrument 记录,可以与 Context 关联。
异步 Instrument(例如 Asynchronous Gauge)为用户提供了一种注册回调函数的方式,回调函数仅在需要时调用(请参阅 SDK collection 作为参考)。例如,一段嵌入式软件可以使用异步 Gauge 每 15 秒收集一次温度传感器读数,这意味着回调函数每 15 秒调用一次。Measurements 由异步 Instrument 记录,不能与 Context 关联。
请注意,术语同步和异步与 asynchronous pattern 无关。
同步 Instrument API
构造同步 Instrument 的 API 必须接受以下参数
Instrument 的
name。name需要由用户提供。如果可能,API 应设计成强制用户提供此参数。如果无法在结构上强制执行此义务,则 API 必须以一种向用户传达此参数必需的方式进行文档记录。API 应以一种向用户传达
name参数需要符合 instrument name syntax 的方式进行文档记录。API 不应验证name;这留给 API 的实现,例如 SDK。度量单位
unit。用户可以提供
unit,但这取决于他们的判断。因此,此 API 需要设计成可以接受unit,但绝不能强制用户提供。unit参数需要支持 instrument unit rule。也就是说,API 必须接受一个区分大小写的字符串,该字符串支持 ASCII 字符编码,并且最多可以容纳 63 个字符。API 不应验证unit。description,以人类可读的术语描述 Instrument。用户可以提供
description,但这取决于他们的判断。因此,此 API 需要设计成可以接受description,但绝不能强制用户提供。description需要支持 instrument description rule。也就是说,API 必须接受一个支持至少 BMP(Unicode Plane 0)编码字符并且最多可以容纳 1023 个字符的字符串。与 instrument
kind关联的advisory参数。用户可以提供
advisory参数,但这取决于他们的判断。因此,此 API 需要设计成可以接受advisory参数,但绝不能强制用户提供。advisory参数需要按照 instrument advisory parameters 中所述的结构进行组织,其中包含通用参数和特定于特定 instrumentkind的参数。API 不应验证advisory参数。
异步 Instrument API
异步 Instrument 具有关联的 callback 函数,这些函数负责报告 Measurements。Callback 函数仅在 Meter 被观察时调用。回调的执行顺序未指定。
构造异步 Instrument 的 API 必须接受以下参数
Instrument 的
name。name需要由用户提供。如果可能,API 应设计成强制用户提供此参数。如果无法在结构上强制执行此义务,则 API 必须以一种向用户传达此参数必需的方式进行文档记录。API 应以一种向用户传达
name参数需要符合 instrument name syntax 的方式进行文档记录。API 不应验证name;这留给 API 的实现。度量单位
unit。用户可以提供
unit,但这取决于他们的判断。因此,此 API 需要设计成可以接受unit,但绝不能强制用户提供。unit参数需要支持 instrument unit rule。也就是说,API 必须接受一个区分大小写的字符串,该字符串支持 ASCII 字符编码,并且最多可以容纳 63 个字符。API 不应验证unit。description,以人类可读的术语描述 Instrument。用户可以提供
description,但这取决于他们的判断。因此,此 API 需要设计成可以接受description,但绝不能强制用户提供。description需要支持 instrument description rule。也就是说,API 必须接受一个支持至少 BMP(Unicode Plane 0)编码字符并且最多可以容纳 1023 个字符的字符串。与 instrument
kind关联的advisory参数。用户可以提供
advisory参数,但这取决于他们的判断。因此,此 API 需要设计成可以接受advisory参数,但绝不能强制用户提供。advisory参数需要按照 instrument advisory parameters 中所述的结构进行组织,其中包含通用参数和特定于特定 instrumentkind的参数。API 不应验证advisory参数。报告所创建 Instrument 的 Measurements 的
callback函数。用户可以提供
callback函数,但这取决于他们的判断。因此,此 API 必须设计成可以接受可变数量的callback函数,包括零个。
API 必须支持通过将零个或多个 callback 函数传递给新创建的 Instrument 来创建异步 Instrument,这些函数将被永久注册。
Callback 是每次通过 OpenTelemetry API 注册 callback 函数时创建的概念实体。
API 应支持在异步 Instrument 创建后注册与它们关联的 callback 函数。
在 API 支持在异步 Instrument 创建后注册 callback 函数的情况下,用户必须能够通过某种方式取消注册特定回调。
在收集过程中,必须对与一组 Instrument 相关的所有当前注册的 Callback 进行求值,每个 Callback 只求值一次,然后才读取该 Instrument 集的数据。
Callback 函数必须为最终用户进行如下文档记录
- Callback 函数应是重入安全的。SDK 期望独立地为每个 MetricReader 求值回调。
- Callback 函数不应花费无限的时间。
- Callback 函数不应发出重复的观测值(具有相同
attributes的多个Measurement)到所有注册的回调中。
当回调违反任何这些建议时,其结果行为在 API 层面未明确指定。
OpenTelemetry API 作者可以决定捕获回调函数中 measurement 的惯用方法。以下是一些示例
- 返回单个
Measurement值的列表(或元组、生成器、枚举器等)。 - 将“Observable Result”作为回调的正式参数传递,其中
result.Observe()捕获单个Measurement值。
在 Instrument 创建时注册的 Callbacks 必须应用于正在构建的单个 Instrument。
在 Instrument 创建后注册的 Callbacks 可能与多个 Instrument 相关联。
多 Instrument Callbacks 的惯用 API 必须区分与每个观测到的 Measurement 值关联的 Instrument。
Multiple-instrument Callbacks 必须在注册时与来自同一 Meter 实例的一组声明的异步 Instrument 相关联。Instrument 必须与 Callbacks 声明性关联的要求允许 SDK 只执行那些对于评估由已配置 View 使用的 Instruments 所必需的回调。
API 必须将单个 Callback 的观测值视为在逻辑上发生在同一时刻,因此在记录时,来自单个 Callback 的观测值必须报告相同的带有相同时间戳。
API 应提供某种方式将 state 传递给回调。 OpenTelemetry API 作者可以决定惯用方法(例如,它可以是回调函数的附加参数,或由 lambda 闭包捕获,或其他东西)。
通用操作
所有 同步 Instrument 都应提供以下功能
Enabled
为了帮助用户避免在记录 measurement 时执行计算成本高昂的操作,同步 Instrument 应提供此 Enabled API。
目前此 API 没有必需的参数。将来可以添加参数,因此,API 必须设计成可以添加参数的方式。
此 API 必须返回一种语言习惯上的布尔类型。返回 true 表示 Instrument 对提供的参数已启用,返回 false 表示 Instrument 对提供的参数已禁用。
返回值并非总是静态的,它可能随时间变化。API 应文档化说明,Instrument 作者需要每次记录 measurement 时调用此 API,以确保获得最新的响应。
Counter
Counter 是一个 同步 Instrument,它支持非负增量。
Counter 的示例用途
- 计算接收到的字节数
- 计算已完成的请求数
- 计算创建的账户数
- 计算运行的检查点数
- 计算 HTTP 5xx 错误数
Counter 创建
除了通过 Meter 创建 Counter 之外,不得有任何其他 API。这可以称为 CreateCounter。如果需要强类型,OpenTelemetry API 作者可以决定语言习惯上的名称,例如 CreateUInt64Counter、CreateDoubleCounter、CreateCounter<UInt64>、CreateCounter<double>。
以下是 OpenTelemetry API 作者可以考虑的一些示例
# Python
exception_counter = meter.create_counter(name="exceptions", description="number of exceptions caught", value_type=int)
// C#
var counterExceptions = meter.CreateCounter<UInt64>("exceptions", description="number of exceptions caught");
readonly struct PowerConsumption
{
[HighCardinality]
string customer;
};
var counterPowerUsed = meter.CreateCounter<double, PowerConsumption>("power_consumption", unit="kWh");
Counter 操作
Add
将 Counter 增加固定量。
此 API 不应返回值(如果某些编程语言或系统需要,它可以返回一个虚拟值,例如 null、undefined)。
此 API 必须接受以下参数
数值增量。
增量值需要由用户提供。如果可能,此 API 应设计成强制用户提供此参数。如果无法在结构上强制执行此义务,则此 API 必须以一种向用户传达此参数必需的方式进行文档记录。
增量值应为非负数。此 API 应以一种向用户传达此值应为非负数的方式进行文档记录。此 API 不应验证此值;这留给 API 的实现。
要与增量值关联的 Attributes。
用户可以提供属性与增量值关联,但这取决于他们的判断。因此,此 API 必须设计成可以接受可变数量的属性,包括零个。
OpenTelemetry API 作者可以决定允许以灵活的方式传递 attributes 作为参数。如果在 counter creation 时提供了属性名称和类型,则 OpenTelemetry API 作者可以允许使用更有效的方式(例如,在调用堆栈上分配的强类型结构、元组)来传递属性值。API 必须允许调用者在调用时提供灵活的属性,而不是在 Instrument 创建期间注册所有可能的属性名称。以下是 OpenTelemetry API 作者可以考虑的一些示例
# Python
exception_counter.add(1, {"exception_type": "IOError", "handled_by_user": True})
exception_counter.add(1, exception_type="IOError", handled_by_user=True)
// C#
counterExceptions.Add(1, ("exception_type", "FileLoadException"), ("handled_by_user", true));
counterPowerUsed.Add(13.5, new PowerConsumption { customer = "Tom" });
counterPowerUsed.Add(200, new PowerConsumption { customer = "Jerry" }, ("is_green_energy", true));
异步 Counter
异步 Counter 是一个 异步 Instrument,当 Instrument 被观察时,它会报告 单调递增的值。
异步 Counter 的示例用途
异步 Counter 创建
除了通过 Meter 创建异步 Counter 外,不得有任何其他 API。这可以称为 CreateObservableCounter。如果需要强类型,OpenTelemetry API 作者可以决定语言习惯上的名称,例如 CreateUInt64ObservableCounter、CreateDoubleObservableCounter、CreateObservableCounter<UInt64>、CreateObservableCounter<double>。
强烈建议使用名称 ObservableCounter(或任何语言习惯上的变体,例如 observable_counter),除非有充分的理由不这样做。请注意,此名称与 asynchronous pattern 和 observer pattern 无关。
注意:与接受增量/差值值的 Counter.Add() 不同,回调函数报告的是 Counter 的绝对值。要确定 Counter 的变化速率,则使用连续测量值之间的差值。
OpenTelemetry API 作者可以决定惯用方法。以下是一些示例
- 返回
Measurements 的列表(或元组、生成器、枚举器等)。 - 使用 observable result 参数以允许报告单个
Measurements。
建议用户代码不要在一个回调中提供超过一个具有相同 attributes 的 Measurement。如果发生这种情况,OpenTelemetry SDK 作者可以决定如何在 SDK 中处理它。例如,在回调调用期间,如果报告了两个 measurement value=1, attributes={pid:4, bitness:64} 和 value=2, attributes={pid:4, bitness:64},OpenTelemetry SDK 作者可以决定只是让它们通过(以便下游消费者可以处理重复项)、丢弃整个数据、选择最后一个,或者其他方式。API 必须将单个 Callback 的观测值视为在逻辑上发生在同一时刻,因此在记录时,来自单个 Callback 的观测值必须报告相同的带有相同时间戳。
API 应提供某种方式将 state 传递给回调。 OpenTelemetry API 作者可以决定惯用方法(例如,它可以是回调函数的附加参数,或由 lambda 闭包捕获,或其他东西)。
以下是 OpenTelemetry API 作者可以考虑的一些示例
# Python
def pf_callback():
# Note: in the real world these would be retrieved from the operating system
return (
(8, ("pid", 0), ("bitness", 64)),
(37741921, ("pid", 4), ("bitness", 64)),
(10465, ("pid", 880), ("bitness", 32)),
)
meter.create_observable_counter(name="PF", description="process page faults", pf_callback)
# Python
def pf_callback(result):
# Note: in the real world these would be retrieved from the operating system
result.Observe(8, ("pid", 0), ("bitness", 64))
result.Observe(37741921, ("pid", 4), ("bitness", 64))
result.Observe(10465, ("pid", 880), ("bitness", 32))
meter.create_observable_counter(name="PF", description="process page faults", pf_callback)
// C#
// A simple scenario where only one value is reported
interface IAtomicClock
{
UInt64 GetCaesiumOscillates();
}
IAtomicClock clock = AtomicClock.Connect();
meter.CreateObservableCounter<UInt64>("caesium_oscillates", () => clock.GetCaesiumOscillates());
异步 Counter 操作
异步 Counter 使用一种惯用的接口,通过在 Asynchronous Counter creation 期间注册的 callback 来报告 measurement。
对于在异步 Instrument 创建后注册的回调函数,API 需要支持一种取消注册机制。例如,从 register_callback 返回的对象可以直接支持 unregister() 方法。
# Python
class Device:
"""A device with one counter"""
def __init__(self, meter, x):
self.x = x
counter = meter.create_observable_counter(name="usage", description="count of items used")
self.cb = counter.register_callback(self.counter_callback)
def counter_callback(self, result):
result.Observe(self.read_counter(), {'x', self.x})
def read_counter(self):
return 100 # ...
def stop(self):
self.cb.unregister()
Histogram
Histogram 是一个 同步 Instrument,可用于报告可能具有统计意义的任意值。它用于诸如直方图、摘要和百分位数的统计。
Histogram 的示例用途
- 请求持续时间
- 响应 payload 的大小
Histogram 创建
除了通过 Meter 创建 Histogram 之外,不得有任何其他 API。这可以称为 CreateHistogram。如果需要强类型,OpenTelemetry API 作者可以决定语言习惯上的名称,例如 CreateUInt64Histogram、CreateDoubleHistogram、CreateHistogram<UInt64>、CreateHistogram<double>。
以下是 OpenTelemetry API 作者可以考虑的一些示例
# Python
http_server_duration = meter.create_histogram(
name="http.server.duration",
description="measures the duration of the inbound HTTP request",
unit="ms",
value_type=float)
// C#
var httpServerDuration = meter.CreateHistogram<double>(
"http.server.duration",
description: "measures the duration of the inbound HTTP request",
unit: "ms"
);
Histogram 操作
Record
使用指定数量更新统计数据。
此 API 不应返回值(如果某些编程语言或系统需要,它可以返回一个虚拟值,例如 null、undefined)。
此 API 必须接受以下参数
要记录的数值。
该值需要由用户提供。如果可能,此 API 应设计成强制用户提供此参数。如果无法在结构上强制执行此义务,则此 API 必须以一种向用户传达此参数必需的方式进行文档记录。
该值应为非负数。此 API 应以一种向用户传达此值应为非负数的方式进行文档记录。此 API 不应验证此值;这留给 API 的实现。
要与值关联的 Attributes。
用户可以提供属性与该值关联,但这取决于他们的判断。因此,此 API 必须设计成可以接受可变数量的属性,包括零个。
OpenTelemetry API 作者 MAY 允许将灵活的 属性 作为单独的参数传递。 OpenTelemetry API 作者 MAY 允许使用更有效的方式(例如,在调用栈上分配的强类型结构、元组)来传递属性值。以下是一些 OpenTelemetry API 作者可以考虑的示例
# Python
http_server_duration.Record(50, {"http.request.method": "POST", "url.scheme": "https"})
http_server_duration.Record(100, http_method="GET", http_scheme="http")
// C#
httpServerDuration.Record(50, ("http.request.method", "POST"), ("url.scheme", "https"));
httpServerDuration.Record(100, new HttpRequestAttributes { method = "GET", scheme = "http" });
Gauge
Gauge 是一个 同步 Instrument,当发生变化时,可用于记录非累加值(例如,背景噪音水平 - 记录来自多个房间的背景噪音水平值并将其相加没有意义)。
注意:如果值是累加的(例如,进程堆大小 - 报告来自多个进程的堆大小并将其相加有意义,这样我们就能得到总堆使用量),请使用 UpDownCounter。
注意:同步 Gauge 通常用于通过订阅更改事件来暴露测量值(即 `backgroundNoiseLevel.onChange(value -> gauge.record(value))`)。如果通过访问器暴露测量值,请使用 Asynchronous Gauge 在回调函数中调用访问器(即 `createObservableGauge(observable -> observable.record(backgroundNoiseLevel.getCurrentValue()))`)。
Gauge 的示例用法
- 订阅背景噪音水平的更改事件
- 订阅 CPU 风扇速度的更改事件
Gauge 创建
除了通过 Meter 创建 Gauge 之外,绝对不应有任何其他 API。这 MAY 调用 CreateGauge。如果需要强类型,OpenTelemetry API 作者 MAY 决定语言惯用名称,例如 CreateUInt64Gauge、CreateDoubleGauge、CreateGauge<UInt64>、CreateGauge<double>。
以下是 OpenTelemetry API 作者可以考虑的一些示例
// Java
DoubleGauge backgroundNoiseLevel = meter.gaugeBuilder("facility.noise.level")
.setDescription("Background noise level of rooms")
.setUnit("B")
.build();
Gauge 操作
记录
记录 Gauge 的当前值。
此 API 不应返回值(如果某些编程语言或系统需要,它可以返回一个虚拟值,例如 null、undefined)。
此 API 必须接受以下参数
一个数值。当前绝对值。
该值需要由用户提供。如果可能,此 API 应设计成强制用户提供此参数。如果无法在结构上强制执行此义务,则此 API 必须以一种向用户传达此参数必需的方式进行文档记录。
要与值关联的 Attributes。
用户可以提供属性与该值关联,但这取决于他们的判断。因此,此 API 必须设计成可以接受可变数量的属性,包括零个。
OpenTelemetry API 作者 MAY 允许将灵活的 属性 作为参数传递。如果在 Gauge 创建期间提供了属性名称和类型,则 OpenTelemetry API 作者 MAY 允许使用更有效的方式(例如,在调用栈上分配的强类型结构、元组)来传递属性值。API 必须允许调用者在调用时提供灵活的属性,而不是在 instrument 创建期间注册所有可能的属性名称。以下是一些 OpenTelemetry API 作者可能考虑的示例
// Java
Attributes roomA = Attributes.builder().put("room.id", "Rack A");
Attributes roomB = Attributes.builder().put("room.id", "Rack B");
backgroundNoiseLevel.record(4.3, roomA);
backgroundNoiseLevel.record(2.5, roomB);
异步 Gauge
Asynchronous Gauge 是一个 异步 Instrument,它在 instrument 被观察时报告非累加值(例如,房间温度 - 记录来自多个房间的温度值并将其相加没有意义)。
注意:如果值是累加的(例如,进程堆大小 - 报告来自多个进程的堆大小并将其相加有意义,这样我们就能得到总堆使用量),请使用 Asynchronous Counter 或 Asynchronous UpDownCounter。
Asynchronous Gauge 的示例用法
- 当前房间温度
- CPU 风扇速度
异步 Gauge 创建
除了通过 Meter 创建 Asynchronous Gauge 之外,绝对不应有任何其他 API。这 MAY 调用 CreateObservableGauge。如果需要强类型,OpenTelemetry API 作者 MAY 决定语言惯用名称,例如 CreateUInt64ObservableGauge、CreateDoubleObservableGauge、CreateObservableGauge<UInt64>、CreateObservableGauge<double>。
强烈建议使用名称 ObservableGauge(或任何语言惯用的变体,例如 observable_gauge),除非有强烈的理由不这样做。请注意,此名称与 异步模式和 观察者模式无关。
以下是 OpenTelemetry API 作者可以考虑的一些示例
# Python
def cpu_frequency_callback():
# Note: in the real world these would be retrieved from the operating system
return (
(3.38, ("cpu", 0), ("core", 0)),
(3.51, ("cpu", 0), ("core", 1)),
(0.57, ("cpu", 1), ("core", 0)),
(0.56, ("cpu", 1), ("core", 1)),
)
meter.create_observable_gauge(
name="cpu.frequency",
description="the real-time CPU clock speed",
callback=cpu_frequency_callback,
unit="GHz",
value_type=float)
# Python
def cpu_frequency_callback(result):
# Note: in the real world these would be retrieved from the operating system
result.Observe(3.38, ("cpu", 0), ("core", 0))
result.Observe(3.51, ("cpu", 0), ("core", 1))
result.Observe(0.57, ("cpu", 1), ("core", 0))
result.Observe(0.56, ("cpu", 1), ("core", 1))
meter.create_observable_gauge(
name="cpu.frequency",
description="the real-time CPU clock speed",
callback=cpu_frequency_callback,
unit="GHz",
value_type=float)
// C#
// A simple scenario where only one value is reported
meter.CreateObservableGauge<double>("temperature", () => sensor.GetTemperature());
异步 Gauge 操作
Asynchronous Gauge 使用惯用的接口,通过在 Asynchronous Gauge 创建期间注册的 callback 来报告测量值。
对于在异步 Instrument 创建后注册的回调函数,API 需要支持一种取消注册机制。例如,从 register_callback 返回的对象可以直接支持 unregister() 方法。
# Python
class Device:
"""A device with one gauge"""
def __init__(self, meter, x):
self.x = x
gauge = meter.create_observable_gauge(name="pressure", description="force/area")
self.cb = gauge.register_callback(self.gauge_callback)
def gauge_callback(self, result):
result.Observe(self.read_gauge(), {'x', self.x})
def read_gauge(self):
return 100 # ...
def stop(self):
self.cb.unregister()
UpDownCounter
UpDownCounter 是一个 同步 Instrument,支持增量和减量。
UpDownCounter 的示例用法
- 活动请求数
- 队列中的项目数
UpDownCounter 适用于绝对值未预先计算或获取“当前值”需要额外工作的场景。如果预先计算的值已可用或获取“当前值”的快照很简单,请改用 Asynchronous UpDownCounter。
UpDownCounter 支持增量地计算集合的大小,例如,报告并发袋中项目数,根据它们添加和删除时的“颜色”和“材质”属性。
| 颜色 | 材质 | 计数 |
|---|---|---|
| 红色 | 铝 | 1 |
| 红色 | 钢 | 2 |
| 蓝色 | 铝 | 0 |
| 蓝色 | 钢 | 5 |
| 黄色 | 铝 | 0 |
| 黄色 | 钢 | 3 |
# Python
items_counter = meter.create_up_down_counter(
name="store.inventory",
description="the number of the items available")
def restock_item(color, material):
inventory.add_item(color=color, material=material)
items_counter.add(1, {"color": color, "material": material})
return true
def sell_item(color, material):
succeeded = inventory.take_item(color=color, material=material)
if succeeded:
items_counter.add(-1, {"color": color, "material": material})
return succeeded
UpDownCounter 创建
除了通过 Meter 创建 UpDownCounter 之外,绝对不应有任何其他 API。这 MAY 调用 CreateUpDownCounter。如果需要强类型,OpenTelemetry API 作者 MAY 决定语言惯用名称,例如 CreateInt64UpDownCounter、CreateDoubleUpDownCounter、CreateUpDownCounter<Int64>、CreateUpDownCounter<double>。
以下是 OpenTelemetry API 作者可以考虑的一些示例
# Python
customers_in_store = meter.create_up_down_counter(
name="grocery.customers",
description="measures the current customers in the grocery store",
value_type=int)
// C#
var customersInStore = meter.CreateUpDownCounter<int>(
"grocery.customers",
description: "measures the current customers in the grocery store",
);
UpDownCounter 操作
添加
按固定金额增量或减量 UpDownCounter。
此 API 不应返回值(如果某些编程语言或系统需要,它可以返回一个虚拟值,例如 null、undefined)。
此 API 必须接受以下参数
要添加的数值。
该值需要由用户提供。如果可能,此 API 应设计成强制用户提供此参数。如果无法在结构上强制执行此义务,则此 API 必须以一种向用户传达此参数必需的方式进行文档记录。
要与值关联的 Attributes。
用户可以提供属性与该值关联,但这取决于他们的判断。因此,此 API 必须设计成可以接受可变数量的属性,包括零个。
OpenTelemetry API 作者 MAY 允许将灵活的 属性 作为单独的参数传递。 OpenTelemetry API 作者 MAY 允许使用更有效的方式(例如,在调用栈上分配的强类型结构、元组)来传递属性值。以下是一些 OpenTelemetry API 作者可以考虑的示例
# Python
customers_in_store.add(1, {"account.type": "commercial"})
customers_in_store.add(-1, account_type="residential")
// C#
customersInStore.Add(1, ("account.type", "commercial"));
customersInStore.Add(-1, new Account { Type = "residential" });
异步 UpDownCounter
Asynchronous UpDownCounter 是一个 异步 Instrument,它在 instrument 被观察时报告累加值(例如,进程堆大小 - 报告来自多个进程的堆大小并将其相加有意义,这样我们就能得到总堆使用量)。
注意:如果值是 单调递增的,请改用 Asynchronous Counter;如果值是非累加的,请改用 Asynchronous Gauge。
Asynchronous UpDownCounter 的示例用法
- 进程堆大小
- 无锁循环缓冲区的近似项目数
异步 UpDownCounter 创建
除了通过 Meter 创建 Asynchronous UpDownCounter 之外,绝对不应有任何其他 API。这 MAY 调用 CreateObservableUpDownCounter。如果需要强类型,OpenTelemetry API 作者 MAY 决定语言惯用名称,例如 CreateUInt64ObservableUpDownCounter、CreateDoubleObservableUpDownCounter、CreateObservableUpDownCounter<UInt64>、CreateObservableUpDownCounter<double>。
强烈建议使用名称 ObservableUpDownCounter(或任何语言惯用的变体,例如 observable_up_down_counter),除非有强烈的理由不这样做。请注意,此名称与 异步模式和 观察者模式无关。
注意:与接受增量/差值值的 UpDownCounter.Add() 不同,回调函数报告 Asynchronous UpDownCounter 的绝对值。要确定 Asynchronous UpDownCounter 正在改变的报告速率,请使用连续测量值之间的差值。
以下是 OpenTelemetry API 作者可以考虑的一些示例
# Python
def ws_callback():
# Note: in the real world these would be retrieved from the operating system
return (
(8, ("pid", 0), ("bitness", 64)),
(20, ("pid", 4), ("bitness", 64)),
(126032, ("pid", 880), ("bitness", 32)),
)
meter.create_observable_up_down_counter(
name="process.workingset",
description="process working set",
callback=ws_callback,
unit="kB",
value_type=int)
# Python
def ws_callback(result):
# Note: in the real world these would be retrieved from the operating system
result.Observe(8, ("pid", 0), ("bitness", 64))
result.Observe(20, ("pid", 4), ("bitness", 64))
result.Observe(126032, ("pid", 880), ("bitness", 32))
meter.create_observable_up_down_counter(
name="process.workingset",
description="process working set",
callback=ws_callback,
unit="kB",
value_type=int)
// C#
// A simple scenario where only one value is reported
meter.CreateObservableUpDownCounter<UInt64>("memory.physical.free", () => WMI.Query("FreePhysicalMemory"));
异步 UpDownCounter 操作
Asynchronous UpDownCounter 使用惯用的接口,通过在 Asynchronous Updowncounter 创建期间注册的 callback 来报告测量值。
对于在异步 Instrument 创建后注册的回调函数,API 需要支持一种取消注册机制。例如,从 register_callback 返回的对象可以直接支持 unregister() 方法。
# Python
class Device:
"""A device with one up_down_counter"""
def __init__(self, meter, x):
self.x = x
updowncounter = meter.create_observable_up_down_counter(name="queue_size", description="items in process")
self.cb = updowncounter.register_callback(self.up_down_counter_callback)
def up_down_counter_callback(self, result):
result.Observe(self.read_up_down_counter(), {'x', self.x})
def read_up_down_counter(self):
return 100 # ...
def stop(self):
self.cb.unregister()
测量
Measurement 代表通过 Metrics API 向 SDK 报告的数据点。有关 API 和 SDK 之间的交互,请参阅 Metrics Programming Model。
Measurement 封装
- 一个值
Attributes
多 Instrument 回调
Metrics API MAY 支持一个接口,允许从单个注册的 Callback 使用多个 Instrument。注册新 Callback 的 API 应该接受
- 一个
callback函数 - 在
callback函数中使用的 Instrument 列表(或元组等)。
建议 API 作者使用以下形式之一来定义 callback 函数
callback函数返回的列表(或元组等)包含(Instrument, Measurement)对。- Observable 结果参数接收额外的
(Instrument, Measurement)对
当测量值是通过昂贵的过程(例如读取 /proc 文件或探测垃圾回收子系统)获得的,此接口通常是报告多个测量值的更有效方式。
例如,
# Python
class Device:
"""A device with two instruments"""
def __init__(self, meter, property):
self.property = property
self.usage = meter.create_observable_counter(name="usage", description="count of items used")
self.pressure = meter.create_observable_gauge(name="pressure", description="force per unit area")
# Note the two associated instruments are passed to the callback.
meter.register_callback([self.usage, self.pressure], self.observe)
def observe(self, result):
usage, pressure = expensive_system_call()
result.observe(self.usage, usage, {'property', self.property})
result.observe(self.pressure, pressure, {'property', self.property})
兼容性要求
所有 Metrics 组件都应允许在不引入破坏性更改的情况下向现有组件添加新 API。
所有 Metrics API 都应允许在不引入破坏性更改的情况下向现有 API 添加可选参数,如果可能的话。
并发要求
对于支持并发执行的语言,Metrics API 提供特定的保证和安全性。
MeterProvider - 所有方法都可以安全地并发调用。
Meter - 所有方法都可以安全地并发调用。
Instrument - 任何 Instrument 的所有方法都可以安全地并发调用。
参考
- OTEP0003 合并预聚合和原始 Metrics API
- OTEP0008 Metrics 观察者规范
- OTEP0009 Metric Handle API 规范
- OTEP0010 在 Metrics API 中将“Cumulative”重命名为“Counter”
- OTEP0049 Metric
LabelSet规范 - OTEP0070 将 Metric Instrument Handles 重命名为“Bound Instruments”
- OTEP0072 Metric 观察者规范(细化)
- OTEP0080 移除 Metric API Gauge Instrument
- OTEP0088 Metric Instruments
- OTEP0090 从 Metrics API 中移除 LabelSet 对象
- OTEP0098 解释 Metric Instruments
- OTEP0108 Metric Instrument 命名指南
- OTEP0146 Scenarios for Metrics API/SDK Prototyping