From 3e3cc818e3995b543c503a2ef7810091996b8bb3 Mon Sep 17 00:00:00 2001 From: Michael Bushe Date: Sun, 13 Sep 2026 23:32:20 +0200 Subject: [PATCH] docs(api): concurrency, instrument name syntax, and histogram value range Three documentation requirements in metrics/api.md that the metrics API did not state. Concurrency (MUST, api.md Concurrency requirements): MeterProvider, Meter and Instrument must each document that implementations need to be safe for concurrent use by default. Added to APIMeterProvider, APIMeter and all seven instruments, using the wording already established for the trace and logs APIs. Instrument name syntax (SHOULD, api.md Synchronous Instrument API): the name parameter doc on all seven create* methods now states the rules, not empty, first character an ASCII letter, then letters, digits, _, ., - or /, at most 255 characters, compared case-insensitively, and says the API does not validate it. Histogram value range (SHOULD, api.md Record): record and recordWithMap now state the value is expected to be non-negative. No check was added; the same section says this API SHOULD NOT validate it. Fixes #72 Fixes #73 Fixes #74 Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 6 +++ lib/src/api/metrics/counter.dart | 5 ++ lib/src/api/metrics/gauge.dart | 5 ++ lib/src/api/metrics/histogram.dart | 11 ++++ lib/src/api/metrics/meter.dart | 54 ++++++++++++++++--- lib/src/api/metrics/meter_provider.dart | 5 ++ lib/src/api/metrics/observable_counter.dart | 5 ++ lib/src/api/metrics/observable_gauge.dart | 5 ++ .../metrics/observable_up_down_counter.dart | 5 ++ lib/src/api/metrics/up_down_counter.dart | 5 ++ 10 files changed, 99 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0911cc..db140dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -107,6 +107,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- The metrics API now documents that `APIMeterProvider`, `APIMeter` and the seven + instruments need to be safe for concurrent use, that an instrument `name` must + conform to the instrument name syntax, and that `Histogram.record` expects a + non-negative value. metrics/api.md makes the first a MUST and the other two a + SHOULD. Comments only, no behavior change + ([#141](https://github.com/MindfulSoftwareLLC/dartastic_opentelemetry_api/pull/141)). - `TraceState` construction (`fromMap`, `OTelAPI`/`OTelFactory` `traceState(...)`) now validates keys and values against the W3C tracestate grammar, dropping invalid entries instead of silently accepting them diff --git a/lib/src/api/metrics/counter.dart b/lib/src/api/metrics/counter.dart index 4ac87e3..0d1e14e 100644 --- a/lib/src/api/metrics/counter.dart +++ b/lib/src/api/metrics/counter.dart @@ -12,6 +12,11 @@ part 'counter_create.dart'; /// /// See the OpenTelemetry specification for more details: /// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#counter +/// +/// All methods of this class are safe for concurrent use by default: +/// implementations must remain correct when methods are invoked from +/// interleaved asynchronous tasks within an isolate. See +/// [Metrics API, concurrency requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#concurrency-requirements). class APICounter { /// The name of this counter instrument. final String _name; diff --git a/lib/src/api/metrics/gauge.dart b/lib/src/api/metrics/gauge.dart index a190f1a..581acdd 100644 --- a/lib/src/api/metrics/gauge.dart +++ b/lib/src/api/metrics/gauge.dart @@ -12,6 +12,11 @@ part 'gauge_create.dart'; /// /// See the OpenTelemetry specification for more details: /// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#gauge +/// +/// All methods of this class are safe for concurrent use by default: +/// implementations must remain correct when methods are invoked from +/// interleaved asynchronous tasks within an isolate. See +/// [Metrics API, concurrency requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#concurrency-requirements). class APIGauge { /// The name of this gauge instrument. final String _name; diff --git a/lib/src/api/metrics/histogram.dart b/lib/src/api/metrics/histogram.dart index c2cd017..567efe5 100644 --- a/lib/src/api/metrics/histogram.dart +++ b/lib/src/api/metrics/histogram.dart @@ -12,6 +12,11 @@ part 'histogram_create.dart'; /// /// See the OpenTelemetry specification for more details: /// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#histogram +/// +/// All methods of this class are safe for concurrent use by default: +/// implementations must remain correct when methods are invoked from +/// interleaved asynchronous tasks within an isolate. See +/// [Metrics API, concurrency requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#concurrency-requirements). class APIHistogram { /// The name of this histogram instrument. final String _name; @@ -70,6 +75,9 @@ class APIHistogram { /// Records a value in the histogram. /// + /// The value is expected to be non-negative. This API does not validate + /// that, which the specification leaves to implementations of the API. + /// /// [value] The value to record. /// [attributes] The set of attributes to associate with this value. void record(T value, [Attributes? attributes]) { @@ -78,6 +86,9 @@ class APIHistogram { /// Records a value with the given map of attributes. /// + /// The value is expected to be non-negative. This API does not validate + /// that, which the specification leaves to implementations of the API. + /// /// [value] The value to record. /// [attributeMap] A map of attribute key-value pairs. void recordWithMap(T value, Map attributeMap) { diff --git a/lib/src/api/metrics/meter.dart b/lib/src/api/metrics/meter.dart index 1013afb..239f578 100644 --- a/lib/src/api/metrics/meter.dart +++ b/lib/src/api/metrics/meter.dart @@ -27,6 +27,11 @@ part 'meter_create.dart'; /// an empty instrument name, and never logs or reports: metrics/noop.md says /// the Meter MUST NOT return a non-empty error or log any message. Name /// validation belongs to the SDK meter. +/// +/// All methods of this class are safe for concurrent use by default: +/// implementations must remain correct when methods are invoked from +/// interleaved asynchronous tasks within an isolate. See +/// [Metrics API, concurrency requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#concurrency-requirements). class APIMeter { /// Gets the name of the meter, usually of a library, package or module final String name; @@ -64,7 +69,12 @@ class APIMeter { /// /// A Counter is a synchronous Instrument which supports non-negative increments. /// - /// [name] The name of the instrument + /// [name] The name of the instrument. It must conform to the instrument + /// name syntax: not empty, first character an ASCII letter, the rest + /// letters, digits, `_`, `.`, `-` or `/`, at most 255 characters, and + /// compared case-insensitively. This API does not validate it; the SDK + /// meter does. See + /// [Instrument name syntax](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#instrument-name-syntax). /// [unit] Optional unit of the instrument (e.g., "ms" for milliseconds) /// [description] Optional description of the instrument APICounter createCounter({ @@ -86,7 +96,12 @@ class APIMeter { /// /// An UpDownCounter is a synchronous Instrument which supports increments and decrements. /// - /// [name] The name of the instrument + /// [name] The name of the instrument. It must conform to the instrument + /// name syntax: not empty, first character an ASCII letter, the rest + /// letters, digits, `_`, `.`, `-` or `/`, at most 255 characters, and + /// compared case-insensitively. This API does not validate it; the SDK + /// meter does. See + /// [Instrument name syntax](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#instrument-name-syntax). /// [unit] Optional unit of the instrument (e.g., "ms" for milliseconds) /// [description] Optional description of the instrument APIUpDownCounter createUpDownCounter({ @@ -109,7 +124,12 @@ class APIMeter { /// A Histogram is a synchronous Instrument which can be used to report arbitrary values /// that are likely to be statistically meaningful. /// - /// [name] The name of the instrument + /// [name] The name of the instrument. It must conform to the instrument + /// name syntax: not empty, first character an ASCII letter, the rest + /// letters, digits, `_`, `.`, `-` or `/`, at most 255 characters, and + /// compared case-insensitively. This API does not validate it; the SDK + /// meter does. See + /// [Instrument name syntax](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#instrument-name-syntax). /// [unit] Optional unit of the instrument (e.g., "ms" for milliseconds) /// [description] Optional description of the instrument /// [boundaries] Optional explicit bucket boundaries for the histogram @@ -146,7 +166,12 @@ class APIMeter { /// A Gauge is a synchronous Instrument which can be used to record non-additive value(s) /// when changes occur. /// - /// [name] The name of the instrument + /// [name] The name of the instrument. It must conform to the instrument + /// name syntax: not empty, first character an ASCII letter, the rest + /// letters, digits, `_`, `.`, `-` or `/`, at most 255 characters, and + /// compared case-insensitively. This API does not validate it; the SDK + /// meter does. See + /// [Instrument name syntax](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#instrument-name-syntax). /// [unit] Optional unit of the instrument (e.g., "ms" for milliseconds) /// [description] Optional description of the instrument APIGauge createGauge({ @@ -169,7 +194,12 @@ class APIMeter { /// An ObservableCounter is an asynchronous Instrument which reports monotonically increasing /// value(s) when the instrument is being observed. /// - /// [name] The name of the instrument + /// [name] The name of the instrument. It must conform to the instrument + /// name syntax: not empty, first character an ASCII letter, the rest + /// letters, digits, `_`, `.`, `-` or `/`, at most 255 characters, and + /// compared case-insensitively. This API does not validate it; the SDK + /// meter does. See + /// [Instrument name syntax](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#instrument-name-syntax). /// [unit] Optional unit of the instrument (e.g., "ms" for milliseconds) /// [description] Optional description of the instrument /// [callback] Optional callback to provide measurements when the instrument is observed @@ -198,7 +228,12 @@ class APIMeter { /// An ObservableUpDownCounter is an asynchronous Instrument which reports values that increase /// or decrease when the instrument is being observed. /// - /// [name] The name of the instrument + /// [name] The name of the instrument. It must conform to the instrument + /// name syntax: not empty, first character an ASCII letter, the rest + /// letters, digits, `_`, `.`, `-` or `/`, at most 255 characters, and + /// compared case-insensitively. This API does not validate it; the SDK + /// meter does. See + /// [Instrument name syntax](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#instrument-name-syntax). /// [unit] Optional unit of the instrument (e.g., "ms" for milliseconds) /// [description] Optional description of the instrument /// [callback] Optional callback to provide measurements when the instrument is observed @@ -227,7 +262,12 @@ class APIMeter { /// An ObservableGauge is an asynchronous Instrument which reports non-additive value(s) /// when the instrument is being observed. /// - /// [name] The name of the instrument + /// [name] The name of the instrument. It must conform to the instrument + /// name syntax: not empty, first character an ASCII letter, the rest + /// letters, digits, `_`, `.`, `-` or `/`, at most 255 characters, and + /// compared case-insensitively. This API does not validate it; the SDK + /// meter does. See + /// [Instrument name syntax](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#instrument-name-syntax). /// [unit] Optional unit of the instrument (e.g., "ms" for milliseconds) /// [description] Optional description of the instrument /// [callback] Optional callback to provide measurements when the instrument is observed diff --git a/lib/src/api/metrics/meter_provider.dart b/lib/src/api/metrics/meter_provider.dart index 6216271..2f52da2 100644 --- a/lib/src/api/metrics/meter_provider.dart +++ b/lib/src/api/metrics/meter_provider.dart @@ -19,6 +19,11 @@ part 'meter_provider_create.dart'; /// ``` /// See [OTel] for creating meters in addition to the default. /// Use [OTelAPI] to run in no-op mode, as required by the specification. +/// +/// All methods of this class are safe for concurrent use by default: +/// implementations must remain correct when methods are invoked from +/// interleaved asynchronous tasks within an isolate. See +/// [Metrics API, concurrency requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#concurrency-requirements). class APIMeterProvider { /// Creates a new [APIMeterProvider]. /// You cannot create a MeterProvider directly; you must use [OTelFactory]: diff --git a/lib/src/api/metrics/observable_counter.dart b/lib/src/api/metrics/observable_counter.dart index 8767aa5..f50ca7a 100644 --- a/lib/src/api/metrics/observable_counter.dart +++ b/lib/src/api/metrics/observable_counter.dart @@ -17,6 +17,11 @@ part 'observable_counter_create.dart'; /// An ObservableCounter is intended for capturing values that can only increase, /// such as the system uptime, the number of total bytes received, or the number /// of page faults. +/// +/// All methods of this class are safe for concurrent use by default: +/// implementations must remain correct when methods are invoked from +/// interleaved asynchronous tasks within an isolate. See +/// [Metrics API, concurrency requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#concurrency-requirements). class APIObservableCounter implements APIObservableInstrument { final String _name; final String? _description; diff --git a/lib/src/api/metrics/observable_gauge.dart b/lib/src/api/metrics/observable_gauge.dart index a9bbbe3..b38d3ab 100644 --- a/lib/src/api/metrics/observable_gauge.dart +++ b/lib/src/api/metrics/observable_gauge.dart @@ -17,6 +17,11 @@ part 'observable_gauge_create.dart'; /// An ObservableGauge is intended for capturing values that are not meant to be combined /// across multiple entities, such as the current temperature, CPU usage percentage, or /// room occupancy. +/// +/// All methods of this class are safe for concurrent use by default: +/// implementations must remain correct when methods are invoked from +/// interleaved asynchronous tasks within an isolate. See +/// [Metrics API, concurrency requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#concurrency-requirements). class APIObservableGauge implements APIObservableInstrument { final String _name; final String? _description; diff --git a/lib/src/api/metrics/observable_up_down_counter.dart b/lib/src/api/metrics/observable_up_down_counter.dart index fa4da91..917ff65 100644 --- a/lib/src/api/metrics/observable_up_down_counter.dart +++ b/lib/src/api/metrics/observable_up_down_counter.dart @@ -16,6 +16,11 @@ part 'observable_up_down_counter_create.dart'; /// /// An ObservableUpDownCounter is intended for capturing values that can increase or /// decrease, such as the current memory usage, active requests, or items in a queue. +/// +/// All methods of this class are safe for concurrent use by default: +/// implementations must remain correct when methods are invoked from +/// interleaved asynchronous tasks within an isolate. See +/// [Metrics API, concurrency requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#concurrency-requirements). class APIObservableUpDownCounter implements APIObservableInstrument { final String _name; diff --git a/lib/src/api/metrics/up_down_counter.dart b/lib/src/api/metrics/up_down_counter.dart index 94806ff..19fda7e 100644 --- a/lib/src/api/metrics/up_down_counter.dart +++ b/lib/src/api/metrics/up_down_counter.dart @@ -12,6 +12,11 @@ part 'up_down_counter_create.dart'; /// /// See the OpenTelemetry specification for more details: /// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#updowncounter +/// +/// All methods of this class are safe for concurrent use by default: +/// implementations must remain correct when methods are invoked from +/// interleaved asynchronous tasks within an isolate. See +/// [Metrics API, concurrency requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/specification/metrics/api.md#concurrency-requirements). class APIUpDownCounter { /// The name of this up-down counter instrument. final String _name;