Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instrument identity, registration conflicts, multi-callback registration, unregister support #2317

Merged
merged 56 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
dc3d5ed
allow duplicate instrument reg
jmacd Jan 18, 2022
80c0e73
comment about single-writer rule and duplicate instruments
jmacd Jan 18, 2022
64c955f
comment about duplicate asynchronous observations
jmacd Jan 18, 2022
e70203c
refer to supp guidelines as well
jmacd Jan 18, 2022
55a1a88
Merge branch 'main' of github.com:open-telemetry/opentelemetry-specif…
jmacd Feb 1, 2022
fc0cfe9
first draft update
jmacd Feb 3, 2022
db71662
Merge branch 'main' of github.com:open-telemetry/opentelemetry-specif…
jmacd Feb 4, 2022
c94358f
pre-merge
jmacd Feb 4, 2022
72d484b
Merge branch 'main' of github.com:open-telemetry/opentelemetry-specif…
jmacd Feb 4, 2022
806317b
finish draft
jmacd Feb 4, 2022
e166181
two edits
jmacd Feb 4, 2022
73d3c03
SDK req
jmacd Feb 4, 2022
0ffc305
intrinsic properties
jmacd Feb 4, 2022
7d5163b
from 2270
jmacd Feb 4, 2022
0778baf
typos
jmacd Feb 4, 2022
bd3056a
add summary
jmacd Feb 4, 2022
65d6147
Require a shorter test for probability sampler
jmacd Feb 4, 2022
f3cbbcc
Update specification/metrics/sdk.md
jmacd Feb 7, 2022
ef78747
Update specification/metrics/datamodel.md
jmacd Feb 7, 2022
fc06d2e
add unit to identity for data points
jmacd Feb 7, 2022
3d27e97
Merge branch 'main' of github.com:open-telemetry/opentelemetry-specif…
jmacd Feb 10, 2022
e9384f0
clarify data model uniqueness
jmacd Feb 10, 2022
40f8ed8
clarify how to report semantic errors and when they can be remediated
jmacd Feb 10, 2022
faf19c1
lint
jmacd Feb 11, 2022
f80bc10
Merge branch 'main' into jmacd/less_prob_sample_test
jmacd Feb 11, 2022
dfc5009
spelling
jmacd Feb 11, 2022
521cb6a
Merge branch 'jmacd/less_prob_sample_test' of github.com:jmacd/opente…
jmacd Feb 11, 2022
841aa47
spelling
jmacd Feb 11, 2022
307e6c2
Merge branch 'main' of github.com:open-telemetry/opentelemetry-specif…
jmacd Feb 11, 2022
eb2430c
Merge branch 'main' of github.com:open-telemetry/opentelemetry-specif…
jmacd Feb 11, 2022
941e11a
Merge branch 'jmacd/less_prob_sample_test' of github.com:jmacd/opente…
jmacd Feb 11, 2022
58e4335
revert mistake unrelated
jmacd Feb 11, 2022
8e93d28
identical and distinct, respectively
jmacd Feb 11, 2022
be56745
refer to API/datamodel spec in SDK spec for conflict res
jmacd Feb 11, 2022
58d20d7
try to clarifyt async observation APIs
jmacd Feb 11, 2022
421ddbc
edits
jmacd Feb 12, 2022
8e56ae6
Update specification/metrics/api.md
jmacd Feb 14, 2022
cb2fa43
Merge branch 'main' of github.com:open-telemetry/opentelemetry-specif…
jmacd Feb 14, 2022
16b1be0
example unregister in python
jmacd Feb 14, 2022
733edcc
Merge branch 'jmacd/dup_instruments' of github.com:jmacd/opentelemetr…
jmacd Feb 14, 2022
5e77317
let multi-instrument be MAY
jmacd Feb 14, 2022
33d6c47
Update specification/metrics/api.md
jmacd Feb 15, 2022
3b13c12
Update specification/metrics/api.md
jmacd Feb 15, 2022
1f4243b
Update specification/metrics/sdk.md
jmacd Feb 15, 2022
84b9bd8
Merge branch 'main' of github.com:open-telemetry/opentelemetry-specif…
jmacd Feb 15, 2022
478b3cd
remove multi-instrument callbacks for now
jmacd Feb 15, 2022
519e854
update examples
jmacd Feb 15, 2022
dba0a00
example text
jmacd Feb 15, 2022
351eea6
remove use of 'context'
jmacd Feb 15, 2022
32c001b
move an SDK req
jmacd Feb 15, 2022
06cbf7d
lint
jmacd Feb 15, 2022
eca822e
Merge branch 'main' of github.com:open-telemetry/opentelemetry-specif…
jmacd Feb 16, 2022
21d2852
Merge branch 'main' into jmacd/dup_instruments
bogdandrutu Feb 17, 2022
8a56608
Fix lint
Feb 17, 2022
6bf3b0a
Merge branch 'main' into jmacd/dup_instruments
Feb 17, 2022
9e1a2d6
Update specification/metrics/api.md
jmacd Feb 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
209 changes: 164 additions & 45 deletions specification/metrics/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,24 @@ This API MUST accept the following parameters:
* [since 1.4.0] `schema_url` (optional): Specifies the Schema URL that should be
recorded in the emitted telemetry.

It is unspecified whether or under which conditions the same or different
`Meter` instances are returned from this functions.

Implementations MUST NOT require users to repeatedly obtain a `Meter` again with
the same name+version+schema_url to pick up configuration changes. This can be
Meters are identified by all of these fields. When more than one
Meter of the same `name`, `version`, and `schema_url` is created, it
is unspecified whether or under which conditions the same or different
jmacd marked this conversation as resolved.
Show resolved Hide resolved
`Meter` instances are returned. The term _identical_ applied to
Meters describes instances where all identifying fields are equal.
The term _distinct_ applied to Meters describes instances where at
least one identifying field has a different value.

Implementations MUST NOT require users to repeatedly obtain a `Meter` with
the same identity to pick up configuration changes. This can be
achieved either by allowing to work with an outdated configuration or by
ensuring that new configuration applies also to previously returned `Meter`s.
bogdandrutu marked this conversation as resolved.
Show resolved Hide resolved

Note: This could, for example, be implemented by storing any mutable
configuration in the `MeterProvider` and having `Meter` implementation objects
have a reference to the `MeterProvider` from which they were obtained. If
configuration must be stored per-meter (such as disabling a certain meter), the
meter could, for example, do a look-up with its name+version+schema_url in a map
meter could, for example, do a look-up with its identity in a map
in the `MeterProvider`, or the `MeterProvider` could maintain a registry of all
returned `Meter`s and actively update their configuration if it changes.

Expand Down Expand Up @@ -174,22 +179,53 @@ Also see the respective sections below for more information on instrument creati
## Instrument

Instruments are used to report [Measurements](#measurement). Each Instrument
will have the following information:
will have the following fields:

* The `name` of the Instrument
* The `kind` of the Instrument - whether it is a [Counter](#counter) or other
instruments, whether it is synchronous or asynchronous
* The `kind` of the Instrument - whether it is a [Counter](#counter) or
one of the other kinds, whether it is synchronous or asynchronous
* An optional `unit` of measure
* An optional `description`

Instruments are associated with the Meter during creation, and are identified by
the name:
Instruments are associated with the Meter during creation. Instruments
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.

<a name="instrument-type-conflict-detection"></a>

When more than one Instrument of the same `name` is created for
identical Meters, denoted _duplicate instrument registration_, the
implementation MUST create a valid Instrument in every case. Here,
"valid" means an instrument that is functional and can be expected to
export data, despite potentially creating a [semantic error in the
data
model](datamodel.md#opentelemetry-protocol-data-model-producer-recommendations).

It is unspecified whether or under which conditions the same or
different Instrument instance will be returned as a result of
duplicate instrument registration. The term _identical_ applied to
Instruments describes instances where all identifying fields are
equal. The term _distinct_ applied to Instruments describes instances
where at least one field value is different.

When more than one distinct Instrument is registered with the same
`name` for identical Meters, the implementation SHOULD emit a warning
to the user informing them of duplicate registration conflict(s).
jmacd marked this conversation as resolved.
Show resolved Hide resolved

* Meter implementations MUST return an error when multiple Instruments are
registered under the same Meter instance using the same name.
* Different Meters MUST be treated as separate namespaces. The names of the
Instruments under one Meter SHOULD NOT interfere with Instruments under
another Meter.
__Note the warning about duplicate Instrument registration conflicts
is meant to help avoid the semantic error state described in the
[OpenTelemetry Metrics data
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.

<a name="instrument-namespace"></a>

Distinct Meters MUST be treated as separate namespaces for the
purposes of detecting [duplicate instrument registration
conflicts](#instrument-type-conflict-detection).

<a name="instrument-naming-rule"></a>

Expand All @@ -212,7 +248,7 @@ DIGIT = %x30-39 ; 0-9

<a name="instrument-unit"></a>

The `unit` is an optional string provided by the author of the instrument. It
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
expected to validate the unit of measurement, or perform the unit conversion).

Expand Down Expand Up @@ -241,7 +277,7 @@ instrument. It MUST be treated as an opaque string from the API and SDK.
* It MUST support at least 1023 characters. [OpenTelemetry
API](../overview.md#api) authors MAY decide if they want to support more.

Instruments can be categorized based on whether they are synchronous or
Instruments are categorized on whether they are synchronous or
asynchronous:

<a name="synchronous-instrument"></a>
Expand All @@ -266,6 +302,26 @@ Please note that the term *synchronous* and *asynchronous* have nothing to do
with the [asynchronous
pattern](https://en.wikipedia.org/wiki/Asynchronous_method_invocation).

The API MUST support creation of asynchronous instruments by passing
zero or more callback functions to be permanently registered to the
newly created instrument. Callbacks functions passed to the
instrument constructor cannot be unregistered.
bogdandrutu marked this conversation as resolved.
Show resolved Hide resolved
jmacd marked this conversation as resolved.
Show resolved Hide resolved

The API SHOULD support registration of callback functions to
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.

Callback functions SHOULD NOT take an indefinite amount of time.
jmacd marked this conversation as resolved.
Show resolved Hide resolved
jmacd marked this conversation as resolved.
Show resolved Hide resolved

Callback functions SHOULD NOT make duplicate observations from asynchronous
instrument callbacks. The resulting behavior when a callback observes
multiple values for identical instrument and attributes is explicitly
not specified.

### Counter

`Counter` is a [synchronous Instrument](#synchronous-instrument) which supports
Expand Down Expand Up @@ -398,9 +454,9 @@ The API MUST accept the following parameters:
rule](#instrument-unit).
* An optional `description`, following the [instrument description
rule](#instrument-description).
* A `callback` function.
* Zero or more `callback` functions. [See the general requirements](#asynchronous-instrument).

The `callback` function is responsible for reporting the
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.
Expand All @@ -410,10 +466,6 @@ callback function reports the absolute value of the counter. To determine the
reported rate the counter is changing, the difference between successive
measurements is used.

The callback function SHOULD NOT take indefinite amount of time. If multiple
independent SDKs coexist in a running process, they MUST invoke the callback
function(s) independently.

[OpenTelemetry API](../overview.md#api) authors MAY decide what is the idiomatic
approach. Here are some examples:

Expand Down Expand Up @@ -484,10 +536,35 @@ meter.CreateObservableCounter<UInt64>("caesium_oscillates", () => clock.GetCaesi

#### Asynchronous Counter operations

Asynchronous Counter is only intended for an asynchronous scenario. The only
operation is provided by the `callback`, which is registered during the
Asynchronous Counter uses an idiomatic interface for reporting
measurements through a `callback`, which is registered during
[Asynchronous Counter creation](#asynchronous-counter-creation).

For callback functions registered after an asynchronous instrument is
created, the API is required to support a mechanism for
unregistration. For example, the object returned from `register_callback`
can support an `unregister()` method directly.

```python
# 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()
jmacd marked this conversation as resolved.
Show resolved Hide resolved
```

### Histogram

`Histogram` is a [synchronous Instrument](#synchronous-instrument) which can be
Expand Down Expand Up @@ -615,17 +692,13 @@ The API MUST accept the following parameters:
rule](#instrument-unit).
* An optional `description`, following the [instrument description
rule](#instrument-description).
* A `callback` function.
* Zero or more `callback` functions. [See the general requirements](#asynchronous-instrument).

The `callback` function is responsible for reporting the
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.

The callback function SHOULD NOT take indefinite amount of time. If multiple
independent SDKs coexist in a running process, they MUST invoke the callback
function(s) independently.

[OpenTelemetry API](../overview.md#api) authors MAY decide what is the idiomatic
approach. Here are some examples:

Expand Down Expand Up @@ -699,10 +772,35 @@ meter.CreateObservableGauge<double>("temperature", () => sensor.GetTemperature()

#### Asynchronous Gauge operations

Asynchronous Gauge is only intended for an asynchronous scenario. The only
operation is provided by the `callback`, which is registered during the
Asynchronous Gauge uses an idiomatic interface for reporting
measurements through a `callback`, which is registered during
[Asynchronous Gauge creation](#asynchronous-gauge-creation).

For callback functions registered after an asynchronous instrument is
created, the API is required to support a mechanism for
unregistration. For example, the object returned from `register_callback`
can support an `unregister()` method directly.

```python
# 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` is a [synchronous Instrument](#synchronous-instrument) which
Expand Down Expand Up @@ -887,9 +985,9 @@ The API MUST accept the following parameters:
rule](#instrument-unit).
* An optional `description`, following the [instrument description
rule](#instrument-description).
* A `callback` function.
* Zero or more `callback` functions. [See the general requirements](#asynchronous-instrument).

The `callback` function is responsible for reporting the
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.
Expand All @@ -899,10 +997,6 @@ 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.

The callback function SHOULD NOT take indefinite amount of time. If multiple
independent SDKs coexist in a running process, they MUST invoke the callback
function(s) independently.

[OpenTelemetry API](../overview.md#api) authors MAY decide what is the idiomatic
approach. Here are some examples:

Expand Down Expand Up @@ -975,9 +1069,34 @@ meter.CreateObservableUpDownCounter<UInt64>("memory.physical.free", () => WMI.Qu

#### Asynchronous UpDownCounter operations

Asynchronous UpDownCounter is only intended for an asynchronous scenario. The
only operation is provided by the `callback`, which is registered during the
[Asynchronous UpDownCounter creation](#asynchronous-updowncounter-creation).
Asynchronous UpDownCounter uses an idiomatic interface for reporting
measurements through a `callback`, which is registered during
[Asynchronous Updowncounter creation](#asynchronous-updowncounter-creation).

For callback functions registered after an asynchronous instrument is
created, the API is required to support a mechanism for
unregistration. For example, the object returned from `register_callback`
can support an `unregister()` method directly.

```python
# Python
class Device:
"""A device with one updowncounter"""

def __init__(self, meter, x):
self.x = x
updowncounter = meter.create_observable_updowncounter(name="queue_size", description="items in process")
self.cb = updowncounter.register_callback(self.updowncounter_callback)

def updowncounter_callback(self, result):
result.Observe(self.read_updowncounter(), {'x', self.x})

def read_updowncounter(self):
return 100 # ...

def stop(self):
self.cb.unregister()
```

## Measurement

Expand All @@ -992,8 +1111,8 @@ for the interaction between the API and SDK.

## Compatibility requirements

All the metrics components SHOULD allow new APIs to be added to existing
components without introducing breaking changes.
All the metrics components SHOULD allow new APIs to be added to
existing components without introducing breaking changes.

All the metrics APIs SHOULD allow optional parameter(s) to be added to existing
APIs without introducing breaking changes, if possible.
Expand Down