diff --git a/specification/metrics/api.md b/specification/metrics/api.md index bda890e90f4..e1b08be10b1 100644 --- a/specification/metrics/api.md +++ b/specification/metrics/api.md @@ -14,6 +14,15 @@ - [Meter](#meter) * [Meter operations](#meter-operations) - [Instrument](#instrument) + * [General characteristics](#general-characteristics) + + [Instrument type conflict detection](#instrument-type-conflict-detection) + + [Instrument namespace](#instrument-namespace) + + [Instrument naming rule](#instrument-naming-rule) + + [Instrument unit](#instrument-unit) + + [Instrument description](#instrument-description) + + [Synchronous and Asynchronous instruments](#synchronous-and-asynchronous-instruments) + + [Synchronous Instrument API](#synchronous-instrument-api) + + [Asynchronous Instrument API](#asynchronous-instrument-api) * [Counter](#counter) + [Counter creation](#counter-creation) + [Counter operations](#counter-operations) @@ -193,7 +202,9 @@ are identified by all of these fields. Language-level features such as the distinction between integer and floating point numbers SHOULD be considered as identifying. - +### General characteristics + +#### Instrument type conflict detection When more than one Instrument of the same `name` is created for identical Meters, denoted *duplicate instrument registration*, the @@ -221,13 +232,13 @@ model](datamodel.md#opentelemetry-protocol-data-model-producer-recommendations) when more than one `Metric` is written for a given instrument `name` and Meter identity by the same MeterProvider. - +#### Instrument namespace Distinct Meters MUST be treated as separate namespaces for the purposes of detecting [duplicate instrument registration conflicts](#instrument-type-conflict-detection). - +#### Instrument naming rule Instrument names MUST conform to the following syntax (described using the [Augmented Backus-Naur Form](https://tools.ietf.org/html/rfc5234)): @@ -246,7 +257,7 @@ DIGIT = %x30-39 ; 0-9 and '-'. * They can have a maximum length of 63 characters. - +#### Instrument unit The `unit` is an optional string provided by the author of the Instrument. It SHOULD be treated as an opaque string from the API and SDK (e.g. the SDK is not @@ -261,7 +272,7 @@ expected to validate the unit of measurement, or perform the unit conversion). runtimes) to be stored and compared as fixed size array/struct when performance is critical. - +#### Instrument description The `description` is an optional free-form text provided by the author of the instrument. It MUST be treated as an opaque string from the API and SDK. @@ -280,7 +291,7 @@ instrument. It MUST be treated as an opaque string from the API and SDK. Instruments are categorized on whether they are synchronous or asynchronous: - +#### Synchronous and Asynchronous instruments * Synchronous instruments (e.g. [Counter](#counter)) are meant to be invoked inline with application/business processing logic. For example, an HTTP client @@ -288,8 +299,6 @@ asynchronous: [Measurements](#measurement) recorded by synchronous instruments can be associated with the [Context](../context/context.md). - - * Asynchronous instruments (e.g. [Asynchronous Gauge](#asynchronous-gauge)) give the user a way to register callback function, and the callback function will be invoked only on demand (see SDK [collection](sdk.md#collect) for reference). For example, a piece of embedded software @@ -302,6 +311,29 @@ Please note that the term *synchronous* and *asynchronous* have nothing to do with the [asynchronous pattern](https://en.wikipedia.org/wiki/Asynchronous_method_invocation). +#### Synchronous Instrument API + +The API to construct synchronous instruments MUST accept the following parameters: + +* The `name` of the Instrument, following the [instrument naming + rule](#instrument-naming-rule). +* An optional `unit` of measure, following the [instrument unit + rule](#instrument-unit). +* An optional `description`, following the [instrument description + rule](#instrument-description). + +#### Asynchronous Instrument API + +The API to construct asynchronous instruments MUST accept the following parameters: + +* The `name` of the Instrument, following the [instrument naming + rule](#instrument-naming-rule). +* An optional `unit` of measure, following the [instrument unit + rule](#instrument-unit). +* An optional `description`, following the [instrument description + rule](#instrument-description). +* Zero or more `callback` functions. + The API MUST support creation of asynchronous instruments by passing zero or more callback functions to be permanently registered to the newly created instrument. @@ -314,6 +346,11 @@ asynchronous instrumentation creation, it MUST return something (e.g., a registration handle, receipt or token) to the user that supports undoing the effect of callback registation. +The `callback` function is responsible for reporting +[Measurement](#measurement)s. It will only be called when the Meter is being +observed. [OpenTelemetry API](../overview.md#api) authors SHOULD define whether +this callback function needs to be reentrant safe / thread safe or not. + Callback functions SHOULD NOT take an indefinite amount of time. Callback functions SHOULD NOT make duplicate observations from asynchronous @@ -321,9 +358,27 @@ instrument callbacks. The resulting behavior when a callback observes multiple values for identical instrument and attributes is explicitly not specified. +[OpenTelemetry API](../overview.md#api) authors MAY decide what is the idiomatic +approach for capturing measurements from callback functions. Here are some examples: + +* Return a list (or tuple, generator, enumerator, etc.) of `Measurement`s. +* Use an observable result argument to allow individual `Measurement`s to be + reported. + +The API MUST treat observations from a single callback as logically +taking place at a single instant, such that when recorded, +observations from a single callback MUST be reported with identical +timestamps. + +The API SHOULD provide some way to pass `state` to the +callback. [OpenTelemetry API](../overview.md#api) authors MAY decide +what is the idiomatic approach (e.g. it could be an additional +parameter to the callback function, or captured by the lambda closure, +or something else). + ### Counter -`Counter` is a [synchronous Instrument](#synchronous-instrument) which supports +`Counter` is a [synchronous Instrument](#synchronous-instrument-api) which supports non-negative increments. Example uses for `Counter`: @@ -342,14 +397,7 @@ desired, [OpenTelemetry API](../overview.md#api) authors MAY decide the language idiomatic name(s), for example `CreateUInt64Counter`, `CreateDoubleCounter`, `CreateCounter`, `CreateCounter`. -The API MUST accept the following parameters: - -* The `name` of the Instrument, following the [instrument naming - rule](#instrument-naming-rule). -* An optional `unit` of measure, following the [instrument unit - rule](#instrument-unit). -* An optional `description`, following the [instrument description - rule](#instrument-description). +See the [general requirements for synchronous instruments](#synchronous-instrument-api). Here are some examples that [OpenTelemetry API](../overview.md#api) authors might consider: @@ -417,7 +465,7 @@ counterPowerUsed.Add(200, new PowerConsumption { customer = "Jerry" }, ("is_gree ### Asynchronous Counter -Asynchronous Counter is an [asynchronous Instrument](#asynchronous-instrument) +Asynchronous Counter is an [asynchronous Instrument](#asynchronous-instrument-api) which reports [monotonically](https://wikipedia.org/wiki/Monotonic_function) increasing value(s) when the instrument is being observed. @@ -445,20 +493,7 @@ a strong reason not to do so. Please note that the name has nothing to do with pattern](https://en.wikipedia.org/wiki/Asynchronous_method_invocation) and [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern). -The API MUST accept the following parameters: - -* The `name` of the Instrument, following the [instrument naming - rule](#instrument-naming-rule). -* An optional `unit` of measure, following the [instrument unit - rule](#instrument-unit). -* An optional `description`, following the [instrument description - rule](#instrument-description). -* Zero or more `callback` functions. [See the general requirements](#asynchronous-instrument). - -The `callback` function is responsible for reporting -[Measurement](#measurement)s. It will only be called when the Meter is being -observed. [OpenTelemetry API](../overview.md#api) authors SHOULD define whether -this callback function needs to be reentrant safe / thread safe or not. +See the [general requirements for asynchronous instruments](#asynchronous-instrument-api). Note: Unlike [Counter.Add()](#add) which takes the increment/delta value, the callback function reports the absolute value of the counter. To determine the @@ -566,7 +601,7 @@ class Device: ### Histogram -`Histogram` is a [synchronous Instrument](#synchronous-instrument) which can be +`Histogram` is a [synchronous Instrument](#synchronous-instrument-api) which can be used to report arbitrary values that are likely to be statistically meaningful. It is intended for statistics such as histograms, summaries, and percentile. @@ -583,14 +618,7 @@ desired, [OpenTelemetry API](../overview.md#api) authors MAY decide the language idiomatic name(s), for example `CreateUInt64Histogram`, `CreateDoubleHistogram`, `CreateHistogram`, `CreateHistogram`. -The API MUST accept the following parameters: - -* The `name` of the Instrument, following the [instrument naming - rule](#instrument-naming-rule). -* An optional `unit` of measure, following the [instrument unit - rule](#instrument-unit). -* An optional `description`, following the [instrument description - rule](#instrument-description). +See the [general requirements for synchronous instruments](#synchronous-instrument-api). Here are some examples that [OpenTelemetry API](../overview.md#api) authors might consider: @@ -652,7 +680,7 @@ httpServerDuration.Record(100, new HttpRequestAttributes { method = "GET", schem ### Asynchronous Gauge -Asynchronous Gauge is an [asynchronous Instrument](#asynchronous-instrument) +Asynchronous Gauge is an [asynchronous Instrument](#asynchronous-instrument-api) which reports non-additive value(s) (e.g. the room temperature - it makes no sense to report the temperature value from multiple rooms and sum them up) when the instrument is being observed. @@ -683,42 +711,7 @@ a strong reason not to do so. Please note that the name has nothing to do with pattern](https://en.wikipedia.org/wiki/Asynchronous_method_invocation) and [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern). -The API MUST accept the following parameters: - -* The `name` of the Instrument, following the [instrument naming - rule](#instrument-naming-rule). -* An optional `unit` of measure, following the [instrument unit - rule](#instrument-unit). -* An optional `description`, following the [instrument description - rule](#instrument-description). -* Zero or more `callback` functions. [See the general requirements](#asynchronous-instrument). - -The `callback` function is responsible for reporting -[Measurement](#measurement)s. It will only be called when the Meter is being -observed. [OpenTelemetry API](../overview.md#api) authors SHOULD define whether -this callback function needs to be reentrant safe / thread safe or not. - -[OpenTelemetry API](../overview.md#api) authors MAY decide what is the idiomatic -approach. Here are some examples: - -* Return a list (or tuple, generator, enumerator, etc.) of `Measurement`s. -* Use an observable result argument to allow individual `Measurement`s to be reported. - -User code is recommended not to provide more than one `Measurement` with the -same `attributes` in a single callback. If it happens, the -[SDK](./README.md#sdk) can decide how to handle it. For example, during the -callback invocation if two measurements `value=3.38, attributes={cpu:1, core:2}` -and `value=3.51, attributes={cpu:1, core:2}` are reported, the SDK can decide to -simply let them pass through (so the downstream consumer can handle -duplication), drop the entire data, pick the last one, or something else. The -API MUST treat observations from a single callback as logically taking place at -a single instant, such that when recorded, observations from a single callback -MUST be reported with identical timestamps. - -The API SHOULD provide some way to pass `state` to the callback. [OpenTelemetry -API](../overview.md#api) authors MAY decide what is the idiomatic approach (e.g. -it could be an additional parameter to the callback function, or captured by the -lambda closure, or something else). +See the [general requirements for asynchronous instruments](#asynchronous-instrument-api). Here are some examples that [OpenTelemetry API](../overview.md#api) authors might consider: @@ -802,7 +795,7 @@ class Device: ### UpDownCounter -`UpDownCounter` is a [synchronous Instrument](#synchronous-instrument) which +`UpDownCounter` is a [synchronous Instrument](#synchronous-instrument-api) which supports increments and decrements. Note: if the value is @@ -878,14 +871,7 @@ idiomatic name(s), for example `CreateInt64UpDownCounter`, `CreateDoubleUpDownCounter`, `CreateUpDownCounter`, `CreateUpDownCounter`. -The API MUST accept the following parameters: - -* The `name` of the Instrument, following the [instrument naming - rule](#instrument-naming-rule). -* An optional `unit` of measure, following the [instrument unit - rule](#instrument-unit). -* An optional `description`, following the [instrument description - rule](#instrument-description). +See the [general requirements for synchronous instruments](#synchronous-instrument-api). Here are some examples that [OpenTelemetry API](../overview.md#api) authors might consider: @@ -944,7 +930,7 @@ customersInStore.Add(-1, new Account { Type = "residential" }); ### Asynchronous UpDownCounter Asynchronous UpDownCounter is an [asynchronous -Instrument](#asynchronous-instrument) which reports additive value(s) (e.g. the +Instrument](#asynchronous-instrument-api) which reports additive value(s) (e.g. the process heap size - it makes sense to report the heap size from multiple processes and sum them up, so we get the total heap usage) when the instrument is being observed. @@ -976,49 +962,13 @@ note that the name has nothing to do with [asynchronous pattern](https://en.wikipedia.org/wiki/Asynchronous_method_invocation) and [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern). -The API MUST accept the following parameters: - -* The `name` of the Instrument, following the [instrument naming - rule](#instrument-naming-rule). -* An optional `unit` of measure, following the [instrument unit - rule](#instrument-unit). -* An optional `description`, following the [instrument description - rule](#instrument-description). -* Zero or more `callback` functions. [See the general requirements](#asynchronous-instrument). - -The `callback` function is responsible for reporting -[Measurement](#measurement)s. It will only be called when the Meter is being -observed. [OpenTelemetry API](../overview.md#api) authors SHOULD define whether -this callback function needs to be reentrant safe / thread safe or not. +See the [general requirements for asynchronous instruments](#asynchronous-instrument-api). Note: Unlike [UpDownCounter.Add()](#add-1) which takes the increment/delta value, the callback function reports the absolute value of the Asynchronous UpDownCounter. To determine the reported rate the Asynchronous UpDownCounter is changing, the difference between successive measurements is used. -[OpenTelemetry API](../overview.md#api) authors MAY decide what is the idiomatic -approach. Here are some examples: - -* Return a list (or tuple, generator, enumerator, etc.) of `Measurement`s. -* Use an observable result argument to allow individual `Measurement`s to be - reported. - -User code is recommended not to provide more than one `Measurement` with the -same `attributes` in a single callback. If it happens, the -[SDK](./README.md#sdk) MAY decide how to handle it. For example, during the -callback invocation if two measurements `value=1, attributes={pid:4, -bitness:64}` and `value=2, attributes={pid:4, bitness:64}` are reported, the SDK -can decide to simply let them pass through (so the downstream consumer can -handle duplication), drop the entire data, pick the last one, or something else. -The API MUST treat observations from a single callback as logically taking place -at a single instant, such that when recorded, observations from a single -callback MUST be reported with identical timestamps. - -The API SHOULD provide some way to pass `state` to the callback. [OpenTelemetry -API](../overview.md#api) authors MAY decide what is the idiomatic approach (e.g. -it could be an additional parameter to the callback function, or captured by the -lambda closure, or something else). - Here are some examples that [OpenTelemetry API](../overview.md#api) authors might consider: diff --git a/specification/metrics/sdk.md b/specification/metrics/sdk.md index d7d0139f6d0..01203d6b9e3 100644 --- a/specification/metrics/sdk.md +++ b/specification/metrics/sdk.md @@ -696,7 +696,7 @@ authors MAY choose the best idiomatic design for their language: #### Collect Collects the metrics from the SDK. If there are [asynchronous -Instruments](./api.md#asynchronous-instrument) involved, their callback +Instruments](./api.md#asynchronous-instrument-api) involved, their callback functions will be triggered. `Collect` SHOULD provide a way to let the caller know whether it succeeded, diff --git a/specification/metrics/supplementary-guidelines.md b/specification/metrics/supplementary-guidelines.md index c41178846cc..c7e08f5287e 100644 --- a/specification/metrics/supplementary-guidelines.md +++ b/specification/metrics/supplementary-guidelines.md @@ -35,8 +35,8 @@ requirements to the existing specifications. The [Instruments](./api.md#instrument) are part of the [Metrics API](./api.md). They allow [Measurements](./api.md#measurement) to be recorded -[synchronously](./api.md#synchronous-instrument) or -[asynchronously](./api.md#asynchronous-instrument). +[synchronously](./api.md#synchronous-instrument-api) or +[asynchronously](./api.md#asynchronous-instrument-api). Choosing the correct instrument is important, because: