Metrics API

Status: Stable, except where otherwise specified

Overview

The Metrics API consists of these main components:

Here is an example of the object hierarchy inside a process instrumented with the 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

Meters can be accessed with a MeterProvider.

In implementations of the API, the MeterProvider is expected to be the stateful object that holds any configuration.

Normally, the MeterProvider is expected to be accessed from a central place. Thus, the API SHOULD provide a way to set/register and access a global default MeterProvider.

MeterProvider operations

The MeterProvider MUST provide the following functions:

  • Get a Meter

Get a Meter

This API MUST accept the following parameters:

  • name: This name uniquely identifies the instrumentation scope, such as the instrumentation library (e.g. io.opentelemetry.contrib.mongodb), package, module or class name. If an application or library has built-in OpenTelemetry instrumentation, both Instrumented library and Instrumentation library can refer to the same library. In that scenario, the name denotes a module name or component name within that library or application.

  • version: Specifies the version of the instrumentation scope if the scope has a version (e.g. a library version). Example value: 1.0.0.

    Users can provide a version, but it is up to their discretion. Therefore, this API needs to be structured to accept a version, but MUST NOT obligate a user to provide one.

  • [since 1.4.0] schema_url: Specifies the Schema URL that should be recorded in the emitted telemetry.

    Users can provide a schema_url, but it is up to their discretion. Therefore, this API needs to be structured to accept a schema_url, but MUST NOT obligate a user to provide one.

  • [since 1.13.0] attributes: Specifies the instrumentation scope attributes to associate with emitted telemetry.

    Users can provide attributes to associate with the instrumentation scope, but it is up to their discretion. Therefore, this API MUST be structured to accept a variable number of attributes, including none.

Meters are identified by name, version, and schema_url 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 Meter instances are returned. It is a user error to create Meters with different attributes but the same identity.

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.

Meter

The meter is responsible for creating Instruments.

Note: Meter SHOULD NOT be responsible for the configuration. This should be the responsibility of the MeterProvider instead.

Meter operations

The Meter MUST provide functions to create new Instruments:

Also see the respective sections below for more information on instrument creation.

Instrument

Instruments are used to report Measurements. Each Instrument will have the following parameters:

  • The name of the Instrument
  • The kind of the Instrument - whether it is a Counter or one of the other kinds, whether it is synchronous or asynchronous
  • An optional unit of measure
  • An optional description
  • Optional advisory parameters (experimental)

Instruments are associated with the Meter during creation. Instruments are identified by the name, kind, unit, and description.

Language-level features such as the distinction between integer and floating point numbers SHOULD be considered as identifying.

The term identical applied to an Instrument describes instances where all identifying fields are equal.

General characteristics

Instrument name syntax

The instrument name syntax is defined below using the 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
  • They are not null or empty strings.
  • They are case-insensitive, ASCII strings.
  • The first character must be an alphabetic character.
  • Subsequent characters must belong to the alphanumeric characters, ‘_’, ‘.’, ‘-’, and ‘/’.
  • They can have a maximum length of 255 characters.

Instrument unit

The unit is an optional string provided by the author of the Instrument. The API SHOULD treat it as an opaque string.

  • It MUST be case-sensitive (e.g. kb and kB are different units), ASCII string.
  • It can have a maximum length of 63 characters. The number 63 is chosen to allow the unit strings (including the \0 terminator on certain language 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. The API MUST treat it as an opaque string.

Instrument advisory parameters

Status: Mixed

advisory parameters are an optional set of recommendations provided by the author of the Instrument, aimed at assisting implementations in providing useful output with minimal configuration. They differ from other parameters in that Implementations MAY ignore advisory parameters.

OpenTelemetry SDKs MUST handle advisory parameters as described here.

advisory parameters may be general, or may be accepted only for specific instrument kinds.

Instrument advisory parameter: ExplicitBucketBoundaries

Status: Stable

Applies to Histogram instrument type.

ExplicitBucketBoundaries (double[]) is the recommended set of bucket boundaries to use if aggregating to explicit bucket Histogram metric data point.

Instrument advisory parameter: Attributes

Status: Experimental

Applies to all instrument types.

Attributes (a list of attribute keys) is the recommended set of attribute keys to be used for the resulting metrics.

Synchronous and Asynchronous instruments

Instruments are categorized on whether they are synchronous or asynchronous:

  • Synchronous instruments (e.g. Counter) are meant to be invoked inline with application/business processing logic. For example, an HTTP client could use a Counter to record the number of bytes it has received. Measurements recorded by synchronous instruments can be associated with the Context.

  • Asynchronous instruments (e.g. Asynchronous Gauge) give the user a way to register callback function, and the callback function will be invoked only on demand (see SDK collection for reference). For example, a piece of embedded software could use an asynchronous gauge to collect the temperature from a sensor every 15 seconds, which means the callback function will only be invoked every 15 seconds. Measurements recorded by asynchronous instruments cannot be associated with the Context.

Please note that the term synchronous and asynchronous have nothing to do with the asynchronous pattern.

Synchronous Instrument API

The API to construct synchronous instruments MUST accept the following parameters:

  • A name of the Instrument.

    The name needs to be provided by a user. If possible, the API SHOULD be structured so a user is obligated to provide this parameter. If it is not possible to structurally enforce this obligation, the API MUST be documented in a way to communicate to users that this parameter is needed.

    The API SHOULD be documented in a way to communicate to users that the name parameter needs to conform to the instrument name syntax. The API SHOULD NOT validate the name; that is left to implementations of the API.

  • A unit of measure.

    Users can provide a unit, but it is up to their discretion. Therefore, this API needs to be structured to accept a unit, but MUST NOT obligate a user to provide one.

    The unit parameter needs to support the instrument unit rule. Meaning, the API MUST accept a case-sensitive string that supports ASCII character encoding and can hold at least 63 characters. The API SHOULD NOT validate the unit.

  • A description describing the Instrument in human-readable terms.

    Users can provide a description, but it is up to their discretion. Therefore, this API needs to be structured to accept a description, but MUST NOT obligate a user to provide one.

    The description needs to support the instrument description rule. Meaning, the API MUST accept a string that supports at least BMP (Unicode Plane 0) encoded characters and hold at least 1023 characters.

  • advisory parameters associated with the instrument kind.

    Users can provide advisory parameters, but its up to their discretion. Therefore, this API needs to be structured to accept advisory parameters, but MUST NOT obligate the user to provide it.

    advisory parameters need to be structured as described in instrument advisory parameters, with parameters that are general and specific to a particular instrument kind. The API SHOULD NOT validate advisory parameters.

Asynchronous Instrument API

Asynchronous instruments have associated callback functions which are responsible for reporting Measurements. Callback functions will be called only when the Meter is being observed. The order of callback execution is not specified.

The API to construct asynchronous instruments MUST accept the following parameters:

  • A name of the Instrument.

    The name needs to be provided by a user. If possible, the API SHOULD be structured so a user is obligated to provide this parameter. If it is not possible to structurally enforce this obligation, the API MUST be documented in a way to communicate to users that this parameter is needed.

    The API SHOULD be documented in a way to communicate to users that the name parameter needs to conform to the instrument name syntax. The API SHOULD NOT validate the name, that is left to implementations of the API.

  • A unit of measure.

    Users can provide a unit, but it is up to their discretion. Therefore, this API needs to be structured to accept a unit, but MUST NOT obligate a user to provide one.

    The unit parameter needs to support the instrument unit rule. Meaning, the API MUST accept a case-sensitive string that supports ASCII character encoding and can hold at least 63 characters. The API SHOULD NOT validate the unit.

  • A description describing the Instrument in human-readable terms.

    Users can provide a description, but it is up to their discretion. Therefore, this API needs to be structured to accept a description, but MUST NOT obligate a user to provide one.

    The description needs to support the instrument description rule. Meaning, the API MUST accept a string that supports at least BMP (Unicode Plane 0) encoded characters and hold at least 1023 characters.

  • advisory parameters associated with the instrument kind.

    Users can provide advisory parameters, but its up to their discretion. Therefore, this API needs to be structured to accept advisory parameters, but MUST NOT obligate the user to provide it.

    advisory parameters need to be structured as described in instrument advisory parameters, with parameters that are general and specific to a particular instrument kind. The API SHOULD NOT validate advisory parameters.

  • callback functions that report Measurements of the created instrument.

    Users can provide callback functions, but it is up to their discretion. Therefore, this API MUST be structured to accept a variable number of callback functions, including none.

The API MUST support creation of asynchronous instruments by passing zero or more callback functions to be permanently registered to the newly created instrument.

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, the user MUST be able to undo registration of the specific callback after its registration by some means.

Every currently registered Callback associated with a set of instruments MUST be evaluated exactly once during collection prior to reading data for that instrument set.

Callback functions MUST be documented as follows for the end user:

  • Callback functions SHOULD be reentrant safe. The SDK expects to evaluate callbacks for each MetricReader independently.
  • Callback functions SHOULD NOT take an indefinite amount of time.
  • Callback functions SHOULD NOT make duplicate observations (more than one Measurement with the same attributes) across all registered callbacks.

The resulting behavior when a callback violates any of these RECOMMENDATIONS is explicitly not specified at the API level.

OpenTelemetry 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 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.

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.

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 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 which supports non-negative increments.

Example uses for Counter:

  • count the number of bytes received
  • count the number of requests completed
  • count the number of accounts created
  • count the number of checkpoints run
  • count the number of HTTP 5xx errors

Counter creation

There MUST NOT be any API for creating a Counter other than with a Meter. This MAY be called CreateCounter. If strong type is desired, OpenTelemetry API authors MAY decide the language idiomatic name(s), for example CreateUInt64Counter, CreateDoubleCounter, CreateCounter<UInt64>, CreateCounter<double>.

See the general requirements for synchronous instruments.

Here are some examples that OpenTelemetry API authors might consider:

# 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 operations

Add

Increment the Counter by a fixed amount.

This API SHOULD NOT return a value (it MAY return a dummy value if required by certain programming languages or systems, for example null, undefined).

This API MUST accept the following parameter:

  • A numeric increment value.

    The increment value needs to be provided by a user. If possible, this API SHOULD be structured so a user is obligated to provide this parameter. If it is not possible to structurally enforce this obligation, this API MUST be documented in a way to communicate to users that this parameter is needed.

    The increment value is expected to be non-negative. This API SHOULD be documented in a way to communicate to users that this value is expected to be non-negative. This API SHOULD NOT validate this value, that is left to implementations of the API.

  • Attributes to associate with the increment value.

    Users can provide attributes to associate with the increment value, but it is up to their discretion. Therefore, this API MUST be structured to accept a variable number of attributes, including none.

The OpenTelemetry API authors MAY decide to allow flexible attributes to be passed in as arguments. If the attribute names and types are provided during the counter creation, the OpenTelemetry API authors MAY allow attribute values to be passed in using a more efficient way (e.g. strong typed struct allocated on the callstack, tuple). The API MUST allow callers to provide flexible attributes at invocation time rather than having to register all the possible attribute names during the instrument creation. Here are some examples that OpenTelemetry API authors might consider:

# 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));