diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a5cbd50720..f9e64720c14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ release. ### Metrics +- Clarify that API support for multi-instrument callbacks is permitted. + ([#2263](https://github.com/open-telemetry/opentelemetry-specification/pull/2263)). - Clarify SDK behavior when view conflicts are present ([#2462](https://github.com/open-telemetry/opentelemetry-specification/pull/2462)). - Clarify MetricReader.Collect result diff --git a/specification/metrics/api.md b/specification/metrics/api.md index cbcf6d055aa..c1189c8de52 100644 --- a/specification/metrics/api.md +++ b/specification/metrics/api.md @@ -45,6 +45,7 @@ + [Asynchronous UpDownCounter creation](#asynchronous-updowncounter-creation) + [Asynchronous UpDownCounter operations](#asynchronous-updowncounter-operations) - [Measurement](#measurement) + * [Multiple-instrument callbacks](#multiple-instrument-callbacks) - [Compatibility requirements](#compatibility-requirements) - [Concurrency requirements](#concurrency-requirements) @@ -337,19 +338,26 @@ The API to construct asynchronous instruments MUST accept the following paramete rule](#instrument-unit). * An optional `description`, following the [instrument description rule](#instrument-description). -* Zero or more `callback` functions. +* Zero or more `callback` functions, responsible for reporting + [Measurement](#measurement) values of the created instrument. The API MUST support creation of asynchronous instruments by passing -zero or more callback functions to be permanently registered to the +zero or more `callback` functions to be permanently registered to the newly created instrument. -The API SHOULD support registration of callback functions to +A Callback is the conceptual entity created each time a `callback` +function is registered through an OpenTelemetry API. + +The API SHOULD support registration of `callback` functions associated with asynchronous instruments after they are created. -Where the API supports registration of callback functions after -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. +Where the API supports registration of `callback` functions after +asynchronous instrumentation creation, the user MUST be able to undo +registration of the specific callback after its registration by some means. + +Every currently registered Callback associated with an instrument MUST +be evaluted exactly once during collection prior to reading data for +that instrument. Callback functions MUST be documented as follows for the end user: @@ -366,11 +374,28 @@ RECOMMENDATIONS is explicitly not specified at the API level. [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. +* Return a list (or tuple, generator, enumerator, etc.) of individual + `Measurement` values. +* Pass an *Observable Result* as a formal parameter of the callback, + where `result.Observe()` captures individual `Measurement` values. + +Callbacks registered at the time of instrument creation MUST apply to +the single instruments which is under construction. -The API MUST treat observations from a single callback as logically +Callbacks registered after the time of instrument creation MAY be +associated with multiple instruments. + +Idiomatic APIs for multiple-instrument Callbacks MUST distinguish the +instrument associated with each observed `Measurement` value. + +Multiple-instrument Callbacks MUST be associated at the time of +registration with a declared set of asynchronous instruments from the +same `Meter` instance. This requirement that Instruments be +declaratively associated with Callbacks allows an SDK to execute only +those Callbacks that are necessary to evaluate instruments that are in +use by a configured [View](sdk.md#view). + +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. @@ -1046,6 +1071,49 @@ for the interaction between the API and SDK. * A value * [`Attributes`](../common/README.md#attribute) +### Multiple-instrument callbacks + +[The Metrics API MAY support an interface allowing the use of multiple +instruments from a single registered +Callback](#asynchronous-instrument-api). The API to register a new +Callback SHOULD accept: + +- A `callback` function +- A list (or tuple, etc.) of Instruments used in the `callback` function. + +It is RECOMMENDED that the API authors use one of the following forms +for the `callback` function: + +* The list (or tuple, etc.) returned by the `callback` function + contains `(Instrument, Measurement)` pairs. +* the Observable Result parameter receives an additional `(Instrument, + Measurement)` pairs + +This interface is typically a more performant way to report multiple +measurements when they are obtained through an expensive process, such +as reading `/proc` files or probing the garbage collection subsystem. + +For example, + +```Python +# Python +class Device: + """A device with two instruments""" + + def __init__(self, meter, proeprty): + 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}) +``` + ## Compatibility requirements All the metrics components SHOULD allow new APIs to be added to