Skip to content

Commit

Permalink
Add an option for multi-instrument callbacks (#2363)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmacd committed Apr 27, 2022
1 parent 0f2f26d commit 9e0d7b9
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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
Expand Down
90 changes: 79 additions & 11 deletions specification/metrics/api.md
Expand Up @@ -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)

Expand Down Expand Up @@ -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:

Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 9e0d7b9

Please sign in to comment.