Line data Source code
1 : // Copyright The OpenTelemetry Authors
2 : // SPDX-License-Identifier: Apache-2.0
3 :
4 : import 'package:dartastic_opentelemetry_api/dartastic_opentelemetry_api.dart';
5 : import 'package:meta/meta.dart';
6 :
7 : import 'instruments/base_instrument.dart';
8 : import 'instruments/counter.dart';
9 : import 'instruments/gauge.dart';
10 : import 'instruments/histogram.dart';
11 : import 'instruments/observable_counter.dart';
12 : import 'instruments/observable_gauge.dart';
13 : import 'instruments/observable_up_down_counter.dart';
14 : import 'instruments/up_down_counter.dart';
15 : import 'meter_provider.dart';
16 :
17 : part 'meter_create.dart';
18 :
19 : /// SDK implementation of the APIMeter interface.
20 : ///
21 : /// A Meter is the entry point for creating instruments that collect measurements for a specific
22 : /// instrumentation scope. Meters are obtained from a MeterProvider, and each Meter is associated
23 : /// with a specific instrumentation library, version, and optional schema URL.
24 : ///
25 : /// The Meter follows the OpenTelemetry metrics data model which consists of instruments that
26 : /// record measurements, which are then aggregated into metrics. This implementation delegates
27 : /// to the API implementation while adding SDK-specific behaviors.
28 : ///
29 : /// More information:
30 : /// https://opentelemetry.io/docs/specs/otel/metrics/api/
31 : /// https://opentelemetry.io/docs/specs/otel/metrics/sdk/
32 : class Meter implements APIMeter {
33 : /// The underlying API Meter implementation.
34 : final APIMeter _delegate;
35 :
36 : /// The MeterProvider that created this Meter.
37 : final MeterProvider _provider;
38 :
39 : /// Private constructor for creating Meter instances.
40 : ///
41 : /// @param delegate The API Meter implementation to delegate to
42 : /// @param provider The MeterProvider that created this Meter
43 33 : Meter._({required APIMeter delegate, required MeterProvider provider})
44 : : _delegate = delegate,
45 : _provider = provider;
46 :
47 : /// Gets the name of the instrumentation scope.
48 : ///
49 : /// This name uniquely identifies the instrumentation library, such as
50 : /// the package, module, or class name.
51 32 : @override
52 64 : String get name => _delegate.name;
53 :
54 : /// Gets the version of the instrumentation scope.
55 : ///
56 : /// This represents the version of the instrumentation library.
57 1 : @override
58 2 : String? get version => _delegate.version;
59 :
60 : /// Gets the schema URL of the instrumentation scope.
61 : ///
62 : /// This URL identifies the schema that defines the instrumentation scope.
63 1 : @override
64 2 : String? get schemaUrl => _delegate.schemaUrl;
65 :
66 : /// Gets the attributes associated with this meter.
67 : ///
68 : /// These attributes provide additional context about the instrumentation scope.
69 1 : @override
70 2 : Attributes? get attributes => _delegate.attributes;
71 :
72 : /// Indicates whether this meter is enabled.
73 : ///
74 : /// If false, instruments created by this meter will not record measurements.
75 : /// This is controlled by the associated MeterProvider.
76 24 : @override
77 48 : bool isEnabled() => _provider.enabled;
78 :
79 : /// Gets the MeterProvider that created this Meter.
80 : ///
81 : /// @return The MeterProvider instance
82 62 : MeterProvider get provider => _provider;
83 :
84 : /// Creates a Counter instrument for recording cumulative, monotonically increasing values.
85 : ///
86 : /// Counters are used to measure a non-negative, monotonically increasing value. They only
87 : /// allow positive increments and are appropriate for values that never decrease, such as
88 : /// request counts, completed operations, or error counts.
89 : ///
90 : /// @param name The name of the instrument, which should be unique within the meter
91 : /// @param unit Optional unit of measurement (e.g., "ms", "bytes", "requests")
92 : /// @param description Optional description of what the instrument measures
93 : /// @return A Counter instrument of the specified numeric type
94 : ///
95 : /// More information:
96 : /// https://opentelemetry.io/docs/specs/otel/metrics/api/#counter
97 18 : @override
98 : APICounter<T> createCounter<T extends num>({
99 : required String name,
100 : String? unit,
101 : String? description,
102 : InstrumentAdvisory? advisory,
103 : }) {
104 : // First call the API implementation to get the API object
105 36 : final apiCounter = _delegate.createCounter<T>(
106 : name: name,
107 : unit: unit,
108 : description: description,
109 : advisory: advisory,
110 : );
111 :
112 : // Now wrap it with our SDK implementation
113 18 : return Counter<T>(apiCounter: apiCounter, meter: this);
114 : }
115 :
116 : /// Creates an UpDownCounter instrument for recording cumulative values that can increase or decrease.
117 : ///
118 : /// UpDownCounters are used to measure values that can go up or down over time. They are appropriate
119 : /// for values that represent a current state, such as active requests, queue size, or resource usage.
120 : ///
121 : /// @param name The name of the instrument, which should be unique within the meter
122 : /// @param unit Optional unit of measurement (e.g., "ms", "bytes", "requests")
123 : /// @param description Optional description of what the instrument measures
124 : /// @return An UpDownCounter instrument of the specified numeric type
125 : ///
126 : /// More information:
127 : /// https://opentelemetry.io/docs/specs/otel/metrics/api/#updowncounter
128 6 : @override
129 : APIUpDownCounter<T> createUpDownCounter<T extends num>({
130 : required String name,
131 : String? unit,
132 : String? description,
133 : InstrumentAdvisory? advisory,
134 : }) {
135 : // First call the API implementation to get the API object
136 12 : final apiCounter = _delegate.createUpDownCounter<T>(
137 : name: name,
138 : unit: unit,
139 : description: description,
140 : advisory: advisory,
141 : );
142 :
143 : // Now wrap it with our SDK implementation
144 6 : return UpDownCounter<T>(apiCounter: apiCounter, meter: this);
145 : }
146 :
147 : /// Creates a Histogram instrument for recording a distribution of values.
148 : ///
149 : /// Histograms are used to measure the distribution of values, such as request durations or
150 : /// response sizes. They provide statistics about the distribution, including count, sum,
151 : /// min, max, and quantiles.
152 : ///
153 : /// @param name The name of the instrument, which should be unique within the meter
154 : /// @param unit Optional unit of measurement (e.g., "ms", "bytes")
155 : /// @param description Optional description of what the instrument measures
156 : /// @param boundaries Deprecated: use `advisory.explicitBucketBoundaries`.
157 : /// When both are given, [boundaries] wins so existing callers keep
158 : /// their buckets.
159 : /// @param advisory Optional advisory parameters; the SDK honors
160 : /// `explicitBucketBoundaries` for the bucket layout
161 : /// @return A Histogram instrument of the specified numeric type
162 : ///
163 : /// More information:
164 : /// https://opentelemetry.io/docs/specs/otel/metrics/api/#histogram
165 8 : @override
166 : APIHistogram<T> createHistogram<T extends num>({
167 : required String name,
168 : String? unit,
169 : String? description,
170 : @Deprecated(
171 : 'Use advisory: InstrumentAdvisory(explicitBucketBoundaries: ...) instead')
172 : List<double>? boundaries,
173 : InstrumentAdvisory? advisory,
174 : }) {
175 : // First call the API implementation to get the API object. It merges
176 : // boundaries into the advisory, so the SDK Histogram reads the
177 : // effective boundaries from apiHistogram.advisory.
178 16 : final apiHistogram = _delegate.createHistogram<T>(
179 : name: name,
180 : unit: unit,
181 : description: description,
182 : // ignore: deprecated_member_use
183 : boundaries: boundaries,
184 : advisory: advisory,
185 : );
186 :
187 : // Now wrap it with our SDK implementation
188 8 : return Histogram<T>(apiHistogram: apiHistogram, meter: this);
189 : }
190 :
191 : /// Creates a Gauge instrument for recording the current value at the time of measurement.
192 : ///
193 : /// Gauges are used to measure the instantaneous value of something, such as the current
194 : /// CPU usage, memory usage, or temperature. They report the most recently observed value.
195 : ///
196 : /// @param name The name of the instrument, which should be unique within the meter
197 : /// @param unit Optional unit of measurement (e.g., "ms", "bytes", "percent")
198 : /// @param description Optional description of what the instrument measures
199 : /// @return A Gauge instrument of the specified numeric type
200 : ///
201 : /// More information:
202 : /// https://opentelemetry.io/docs/specs/otel/metrics/api/#gauge
203 7 : @override
204 : APIGauge<T> createGauge<T extends num>({
205 : required String name,
206 : String? unit,
207 : String? description,
208 : InstrumentAdvisory? advisory,
209 : }) {
210 : // First call the API implementation to get the API object
211 14 : final apiGauge = _delegate.createGauge<T>(
212 : name: name,
213 : unit: unit,
214 : description: description,
215 : advisory: advisory,
216 : );
217 :
218 : // Now wrap it with our SDK implementation
219 7 : return Gauge<T>(apiGauge: apiGauge, meter: this);
220 : }
221 :
222 : /// Creates an ObservableCounter instrument for asynchronously recording cumulative, monotonically increasing values.
223 : ///
224 : /// ObservableCounters are used when measurements are expensive to compute and should be
225 : /// collected only when needed, or when they come from an external source. They are appropriate
226 : /// for the same use cases as Counters, but with asynchronous collection.
227 : ///
228 : /// @param name The name of the instrument, which should be unique within the meter
229 : /// @param unit Optional unit of measurement (e.g., "ms", "bytes", "requests")
230 : /// @param description Optional description of what the instrument measures
231 : /// @param advisory Optional advisory parameters for the instrument
232 : /// @param callbacks Callback functions invoked when measurements are collected
233 : /// @param callback Deprecated: use [callbacks]; a [callback] is prepended to it
234 : /// @return An ObservableCounter instrument of the specified numeric type
235 : ///
236 : /// More information:
237 : /// https://opentelemetry.io/docs/specs/otel/metrics/api/#asynchronous-counter
238 11 : @override
239 : APIObservableCounter<T> createObservableCounter<T extends num>({
240 : required String name,
241 : String? unit,
242 : String? description,
243 : InstrumentAdvisory? advisory,
244 : List<ObservableCallback<T>> callbacks = const [],
245 : @Deprecated('Use callbacks instead') ObservableCallback<T>? callback,
246 : }) {
247 : // First call the API implementation to get the API object. It merges
248 : // the deprecated callback into callbacks.
249 22 : final apiCounter = _delegate.createObservableCounter<T>(
250 : name: name,
251 : unit: unit,
252 : description: description,
253 : advisory: advisory,
254 : callbacks: callbacks,
255 : // ignore: deprecated_member_use
256 : callback: callback,
257 : );
258 :
259 : // Now wrap it with our SDK implementation
260 11 : final counter = ObservableCounter<T>(apiCounter: apiCounter, meter: this);
261 :
262 : // Register the instrument with the meter provider
263 22 : _provider.registerInstrument(name, counter);
264 :
265 : return counter;
266 : }
267 :
268 : /// Creates an ObservableUpDownCounter instrument for asynchronously recording cumulative values that can increase or decrease.
269 : ///
270 : /// ObservableUpDownCounters are used when measurements are expensive to compute and should be
271 : /// collected only when needed, or when they come from an external source. They are appropriate
272 : /// for the same use cases as UpDownCounters, but with asynchronous collection.
273 : ///
274 : /// @param name The name of the instrument, which should be unique within the meter
275 : /// @param unit Optional unit of measurement (e.g., "ms", "bytes", "requests")
276 : /// @param description Optional description of what the instrument measures
277 : /// @param advisory Optional advisory parameters for the instrument
278 : /// @param callbacks Callback functions invoked when measurements are collected
279 : /// @param callback Deprecated: use [callbacks]; a [callback] is prepended to it
280 : /// @return An ObservableUpDownCounter instrument of the specified numeric type
281 : ///
282 : /// More information:
283 : /// https://opentelemetry.io/docs/specs/otel/metrics/api/#asynchronous-updowncounter
284 8 : @override
285 : APIObservableUpDownCounter<T> createObservableUpDownCounter<T extends num>({
286 : required String name,
287 : String? unit,
288 : String? description,
289 : InstrumentAdvisory? advisory,
290 : List<ObservableCallback<T>> callbacks = const [],
291 : @Deprecated('Use callbacks instead') ObservableCallback<T>? callback,
292 : }) {
293 : // First call the API implementation to get the API object. It merges
294 : // the deprecated callback into callbacks.
295 16 : final apiCounter = _delegate.createObservableUpDownCounter<T>(
296 : name: name,
297 : unit: unit,
298 : description: description,
299 : advisory: advisory,
300 : callbacks: callbacks,
301 : // ignore: deprecated_member_use
302 : callback: callback,
303 : );
304 :
305 : // Now wrap it with our SDK implementation
306 8 : final counter = ObservableUpDownCounter<T>(
307 : apiCounter: apiCounter,
308 : meter: this,
309 : );
310 :
311 : // Register the instrument with the meter provider
312 16 : _provider.registerInstrument(name, counter);
313 :
314 : return counter;
315 : }
316 :
317 : /// Creates an ObservableGauge instrument for asynchronously recording the current value at collection time.
318 : ///
319 : /// ObservableGauges are used when measurements are expensive to compute and should be
320 : /// collected only when needed, or when they come from an external source. They are appropriate
321 : /// for the same use cases as Gauges, but with asynchronous collection.
322 : ///
323 : /// @param name The name of the instrument, which should be unique within the meter
324 : /// @param unit Optional unit of measurement (e.g., "ms", "bytes", "percent")
325 : /// @param description Optional description of what the instrument measures
326 : /// @param advisory Optional advisory parameters for the instrument
327 : /// @param callbacks Callback functions invoked when measurements are collected
328 : /// @param callback Deprecated: use [callbacks]; a [callback] is prepended to it
329 : /// @return An ObservableGauge instrument of the specified numeric type
330 : ///
331 : /// More information:
332 : /// https://opentelemetry.io/docs/specs/otel/metrics/api/#asynchronous-gauge
333 8 : @override
334 : APIObservableGauge<T> createObservableGauge<T extends num>({
335 : required String name,
336 : String? unit,
337 : String? description,
338 : InstrumentAdvisory? advisory,
339 : List<ObservableCallback<T>> callbacks = const [],
340 : @Deprecated('Use callbacks instead') ObservableCallback<T>? callback,
341 : }) {
342 : // First call the API implementation to get the API object. It merges
343 : // the deprecated callback into callbacks.
344 16 : final apiGauge = _delegate.createObservableGauge<T>(
345 : name: name,
346 : unit: unit,
347 : description: description,
348 : advisory: advisory,
349 : callbacks: callbacks,
350 : // ignore: deprecated_member_use
351 : callback: callback,
352 : );
353 :
354 : // Now wrap it with our SDK implementation
355 8 : final gauge = ObservableGauge<T>(apiGauge: apiGauge, meter: this);
356 :
357 : // Register the instrument with the meter provider
358 16 : _provider.registerInstrument(name, gauge);
359 :
360 : return gauge;
361 : }
362 :
363 : /// Batch callbacks registered through [registerBatchCallback], run once
364 : /// per collection by [MeterProvider.collectAllMetrics].
365 : final List<_BatchCallbackRegistration> _batchCallbacks = [];
366 :
367 : /// Registers one callback that observes several of this meter's
368 : /// asynchronous instruments at once.
369 : ///
370 : /// Per metrics/api.md the instruments MUST all belong to this meter; an
371 : /// instrument from another meter, or one that is not an SDK asynchronous
372 : /// instrument, is reported through [OTelErrorHandling] and the callback is
373 : /// not registered. The returned registration's `unregister()` stops the
374 : /// callback from being invoked on later collections.
375 1 : @override
376 : APIBatchCallbackRegistration registerBatchCallback(
377 : BatchObservableCallback callback,
378 : Set<APIObservableInstrument> instruments,
379 : ) {
380 2 : for (final instrument in instruments) {
381 1 : if (!identical(instrument.meter, this) ||
382 1 : instrument is! SDKObservableInstrument) {
383 3 : OTelErrorHandling.report(ArgumentError(
384 1 : 'registerBatchCallback: instrument "${instrument.name}" belongs '
385 : 'to a different Meter; the callback was not registered.',
386 : ));
387 1 : return _NoopBatchCallbackRegistration();
388 : }
389 : }
390 1 : final registration = _BatchCallbackRegistration(
391 : meter: this,
392 : callback: callback,
393 2 : instruments: instruments.cast<SDKObservableInstrument>().toSet(),
394 : );
395 2 : _batchCallbacks.add(registration);
396 : return registration;
397 : }
398 :
399 : /// Invokes every registered batch callback once, queuing its observations
400 : /// on the instruments it covers for their next `collect()`.
401 : ///
402 : /// Called by [MeterProvider.collectAllMetrics] before the instruments
403 : /// collect. A callback that throws is reported and the rest still run.
404 16 : void runBatchCallbacks() {
405 48 : if (!isEnabled() || _batchCallbacks.isEmpty) return;
406 3 : for (final registration in List.of(_batchCallbacks)) {
407 2 : final result = _BatchObservableResult(registration.instruments);
408 : try {
409 2 : registration.callback(result);
410 : } catch (e, stackTrace) {
411 1 : OTelErrorHandling.report(e, stackTrace);
412 : }
413 : }
414 : }
415 : }
416 :
417 : /// A live registration for a batch callback on an SDK [Meter].
418 : class _BatchCallbackRegistration implements APIBatchCallbackRegistration {
419 : final Meter meter;
420 : final BatchObservableCallback callback;
421 : final Set<SDKObservableInstrument> instruments;
422 :
423 1 : _BatchCallbackRegistration({
424 : required this.meter,
425 : required this.callback,
426 : required this.instruments,
427 : });
428 :
429 1 : @override
430 : void unregister() {
431 3 : meter._batchCallbacks.remove(this);
432 : }
433 : }
434 :
435 : /// Registration handed back when a batch callback was rejected or the meter
436 : /// is a no-op; unregistering it does nothing.
437 : class _NoopBatchCallbackRegistration implements APIBatchCallbackRegistration {
438 1 : @override
439 : void unregister() {}
440 : }
441 :
442 : /// The [BatchObservableResult] handed to a batch callback.
443 : ///
444 : /// An observation for an instrument the callback was not registered with is
445 : /// dropped and reported, per metrics/api.md ("the callback SHOULD only
446 : /// report observations for the instruments it was registered with").
447 : class _BatchObservableResult implements BatchObservableResult {
448 : final Set<SDKObservableInstrument> _instruments;
449 :
450 1 : _BatchObservableResult(this._instruments);
451 :
452 1 : @override
453 : void observe(APIObservableInstrument instrument, num value,
454 : [Attributes? attributes]) {
455 1 : if (instrument is! SDKObservableInstrument ||
456 2 : !_instruments.contains(instrument)) {
457 3 : OTelErrorHandling.report(ArgumentError(
458 1 : 'Batch callback observed instrument "${instrument.name}", which it '
459 : 'was not registered with; the observation was dropped.',
460 : ));
461 : return;
462 : }
463 1 : instrument.observeFromBatch(value, attributes);
464 : }
465 : }
466 :
467 : /// A no-op implementation of Meter that doesn't record any metrics.
468 : ///
469 : /// This implementation is used when the MeterProvider has been shut down
470 : /// or if metrics collection is disabled. It provides the same interface as
471 : /// a regular Meter but does nothing when measurements are recorded.
472 : ///
473 : /// More information:
474 : /// https://opentelemetry.io/docs/specs/otel/metrics/api/#no-op-implementations
475 : class NoopMeter implements APIMeter {
476 : @override
477 : final String name;
478 :
479 : @override
480 : final String? version;
481 :
482 : @override
483 : final String? schemaUrl;
484 :
485 : @override
486 : final Attributes? attributes = null;
487 :
488 1 : @override
489 : bool isEnabled() => false;
490 :
491 : /// Creates a new NoopMeter with the specified name and optional version and schema URL.
492 : ///
493 : /// @param name The name of the instrumentation scope
494 : /// @param version Optional version of the instrumentation scope
495 : /// @param schemaUrl Optional URL of the schema defining the instrumentation scope
496 4 : NoopMeter({required this.name, this.version, this.schemaUrl});
497 :
498 1 : @override
499 : APICounter<T> createCounter<T extends num>({
500 : required String name,
501 : String? unit,
502 : String? description,
503 : InstrumentAdvisory? advisory,
504 : }) {
505 1 : return NoopCounter<T>(
506 : name: name,
507 : unit: unit,
508 : description: description,
509 : advisory: advisory,
510 : );
511 : }
512 :
513 1 : @override
514 : APIUpDownCounter<T> createUpDownCounter<T extends num>({
515 : required String name,
516 : String? unit,
517 : String? description,
518 : InstrumentAdvisory? advisory,
519 : }) {
520 1 : return NoopUpDownCounter<T>(
521 : name: name,
522 : unit: unit,
523 : description: description,
524 : advisory: advisory,
525 : );
526 : }
527 :
528 2 : @override
529 : APIHistogram<T> createHistogram<T extends num>({
530 : required String name,
531 : String? unit,
532 : String? description,
533 : @Deprecated(
534 : 'Use advisory: InstrumentAdvisory(explicitBucketBoundaries: ...) instead')
535 : List<double>? boundaries,
536 : InstrumentAdvisory? advisory,
537 : }) {
538 2 : return NoopHistogram<T>(
539 : name: name,
540 : unit: unit,
541 : description: description,
542 : advisory: boundaries != null
543 2 : ? InstrumentAdvisory(
544 : explicitBucketBoundaries: boundaries,
545 0 : attributeKeys: advisory?.attributeKeys,
546 : )
547 : : advisory,
548 : );
549 : }
550 :
551 1 : @override
552 : APIGauge<T> createGauge<T extends num>({
553 : required String name,
554 : String? unit,
555 : String? description,
556 : InstrumentAdvisory? advisory,
557 : }) {
558 1 : return NoopGauge<T>(
559 : name: name,
560 : unit: unit,
561 : description: description,
562 : advisory: advisory,
563 : );
564 : }
565 :
566 1 : @override
567 : APIObservableCounter<T> createObservableCounter<T extends num>({
568 : required String name,
569 : String? unit,
570 : String? description,
571 : InstrumentAdvisory? advisory,
572 : List<ObservableCallback<T>> callbacks = const [],
573 : @Deprecated('Use callbacks instead') ObservableCallback<T>? callback,
574 : }) {
575 1 : return NoopObservableCounter<T>(
576 : name: name,
577 : unit: unit,
578 : description: description,
579 : advisory: advisory,
580 2 : callbacks: [if (callback != null) callback, ...callbacks],
581 : );
582 : }
583 :
584 1 : @override
585 : APIObservableUpDownCounter<T> createObservableUpDownCounter<T extends num>({
586 : required String name,
587 : String? unit,
588 : String? description,
589 : InstrumentAdvisory? advisory,
590 : List<ObservableCallback<T>> callbacks = const [],
591 : @Deprecated('Use callbacks instead') ObservableCallback<T>? callback,
592 : }) {
593 1 : return NoopObservableUpDownCounter<T>(
594 : name: name,
595 : unit: unit,
596 : description: description,
597 : advisory: advisory,
598 2 : callbacks: [if (callback != null) callback, ...callbacks],
599 : );
600 : }
601 :
602 2 : @override
603 : APIObservableGauge<T> createObservableGauge<T extends num>({
604 : required String name,
605 : String? unit,
606 : String? description,
607 : InstrumentAdvisory? advisory,
608 : List<ObservableCallback<T>> callbacks = const [],
609 : @Deprecated('Use callbacks instead') ObservableCallback<T>? callback,
610 : }) {
611 2 : return NoopObservableGauge<T>(
612 : name: name,
613 : unit: unit,
614 : description: description,
615 : advisory: advisory,
616 4 : callbacks: [if (callback != null) callback, ...callbacks],
617 : );
618 : }
619 :
620 1 : @override
621 : APIBatchCallbackRegistration registerBatchCallback(
622 : BatchObservableCallback callback,
623 : Set<APIObservableInstrument> instruments,
624 : ) {
625 1 : return _NoopBatchCallbackRegistration();
626 : }
627 : }
628 :
629 : /// No-op implementation of Counter instrument.
630 : ///
631 : /// This implementation conforms to the OpenTelemetry specification for no-op implementations,
632 : /// maintaining the same interface as a functional Counter but performing no operations.
633 : class NoopCounter<T extends num> implements APICounter<T> {
634 : @override
635 : final String name;
636 :
637 : @override
638 : final String? description;
639 :
640 : @override
641 : final String? unit;
642 :
643 1 : @override
644 : bool isEnabled() => false;
645 :
646 : @override
647 : final APIMeter meter;
648 :
649 : /// Creates a new NoopCounter with the specified name, unit, and description.
650 : ///
651 : /// @param name The name of the instrument
652 : /// @param unit Optional unit of measurement
653 : /// @param description Optional description of what the instrument measures
654 : @override
655 : final InstrumentAdvisory? advisory;
656 :
657 1 : NoopCounter({required this.name, this.unit, this.description, this.advisory})
658 1 : : meter = NoopMeter(name: 'noop-meter');
659 :
660 : /// Records a measurement (no-op implementation).
661 : ///
662 : /// @param value The measurement value (ignored)
663 : /// @param attributes Optional attributes to associate with the measurement (ignored)
664 1 : @override
665 : void add(T value, [Attributes? attributes]) {
666 : // No-op
667 : }
668 :
669 : /// Records a measurement with attributes as a map (no-op implementation).
670 : ///
671 : /// @param value The measurement value (ignored)
672 : /// @param attributeMap Map of attribute names to values (ignored)
673 1 : @override
674 : void addWithMap(T value, Map<String, Object> attributeMap) {
675 : // No-op
676 : }
677 :
678 1 : @override
679 : bool get isCounter => true;
680 :
681 1 : @override
682 : bool get isGauge => false;
683 :
684 1 : @override
685 : bool get isHistogram => false;
686 :
687 1 : @override
688 : bool get isUpDownCounter => false;
689 : }
690 :
691 : /// No-op implementation of UpDownCounter instrument.
692 : ///
693 : /// This implementation conforms to the OpenTelemetry specification for no-op implementations,
694 : /// maintaining the same interface as a functional UpDownCounter but performing no operations.
695 : class NoopUpDownCounter<T extends num> implements APIUpDownCounter<T> {
696 : @override
697 : final String name;
698 :
699 : @override
700 : final String? description;
701 :
702 : @override
703 : final String? unit;
704 :
705 1 : @override
706 : bool isEnabled() => false;
707 :
708 : @override
709 : final APIMeter meter;
710 :
711 : /// Creates a new NoopUpDownCounter with the specified name, unit, and description.
712 : ///
713 : /// @param name The name of the instrument
714 : /// @param unit Optional unit of measurement
715 : /// @param description Optional description of what the instrument measures
716 : @override
717 : final InstrumentAdvisory? advisory;
718 :
719 1 : NoopUpDownCounter(
720 : {required this.name, this.unit, this.description, this.advisory})
721 1 : : meter = NoopMeter(name: 'noop-meter');
722 :
723 : /// Records a measurement (no-op implementation).
724 : ///
725 : /// @param value The measurement value (ignored)
726 : /// @param attributes Optional attributes to associate with the measurement (ignored)
727 1 : @override
728 : void add(T value, [Attributes? attributes]) {
729 : // No-op
730 : }
731 :
732 : /// Records a measurement with attributes as a map (no-op implementation).
733 : ///
734 : /// @param value The measurement value (ignored)
735 : /// @param attributeMap Map of attribute names to values (ignored)
736 1 : @override
737 : void addWithMap(T value, Map<String, Object> attributeMap) {
738 : // No-op
739 : }
740 :
741 1 : @override
742 : bool get isCounter => false;
743 :
744 1 : @override
745 : bool get isGauge => false;
746 :
747 1 : @override
748 : bool get isHistogram => false;
749 :
750 1 : @override
751 : bool get isUpDownCounter => true;
752 : }
753 :
754 : /// No-op implementation of Histogram instrument.
755 : ///
756 : /// This implementation conforms to the OpenTelemetry specification for no-op implementations,
757 : /// maintaining the same interface as a functional Histogram but performing no operations.
758 : class NoopHistogram<T extends num> implements APIHistogram<T> {
759 : @override
760 : final String name;
761 :
762 : @override
763 : final String? description;
764 :
765 : @override
766 : final String? unit;
767 :
768 : @override
769 : final InstrumentAdvisory? advisory;
770 :
771 0 : @Deprecated('Use advisory?.explicitBucketBoundaries instead')
772 : @override
773 0 : List<double>? get boundaries => advisory?.explicitBucketBoundaries;
774 :
775 1 : @override
776 : bool isEnabled() => false;
777 :
778 : @override
779 : final APIMeter meter;
780 :
781 : /// Creates a new NoopHistogram with the specified name, unit, description, and advisory.
782 : ///
783 : /// @param name The name of the instrument
784 : /// @param unit Optional unit of measurement
785 : /// @param description Optional description of what the instrument measures
786 : /// @param advisory Optional advisory parameters, carrying any bucket boundaries
787 2 : NoopHistogram({
788 : required this.name,
789 : this.unit,
790 : this.description,
791 : this.advisory,
792 2 : }) : meter = NoopMeter(name: 'noop-meter');
793 :
794 : /// Records a measurement (no-op implementation).
795 : ///
796 : /// @param value The measurement value (ignored)
797 : /// @param attributes Optional attributes to associate with the measurement (ignored)
798 1 : @override
799 : void record(T value, [Attributes? attributes]) {
800 : // No-op
801 : }
802 :
803 : /// Records a measurement with attributes as a map (no-op implementation).
804 : ///
805 : /// @param value The measurement value (ignored)
806 : /// @param attributeMap Map of attribute names to values (ignored)
807 1 : @override
808 : void recordWithMap(T value, Map<String, Object> attributeMap) {
809 : // No-op
810 : }
811 :
812 1 : @override
813 : bool get isCounter => false;
814 :
815 1 : @override
816 : bool get isGauge => false;
817 :
818 1 : @override
819 : bool get isHistogram => true;
820 :
821 1 : @override
822 : bool get isUpDownCounter => false;
823 : }
824 :
825 : /// No-op implementation of Gauge instrument.
826 : ///
827 : /// This implementation conforms to the OpenTelemetry specification for no-op implementations,
828 : /// maintaining the same interface as a functional Gauge but performing no operations.
829 : class NoopGauge<T extends num> implements APIGauge<T> {
830 : @override
831 : final String name;
832 :
833 : @override
834 : final String? description;
835 :
836 : @override
837 : final String? unit;
838 :
839 1 : @override
840 : bool isEnabled() => false;
841 :
842 : @override
843 : final APIMeter meter;
844 :
845 : /// Creates a new NoopGauge with the specified name, unit, and description.
846 : ///
847 : /// @param name The name of the instrument
848 : /// @param unit Optional unit of measurement
849 : /// @param description Optional description of what the instrument measures
850 : @override
851 : final InstrumentAdvisory? advisory;
852 :
853 1 : NoopGauge({required this.name, this.unit, this.description, this.advisory})
854 1 : : meter = NoopMeter(name: 'noop-meter');
855 :
856 : /// Records a measurement (no-op implementation).
857 : ///
858 : /// @param value The measurement value (ignored)
859 : /// @param attributes Optional attributes to associate with the measurement (ignored)
860 1 : @override
861 : void record(T value, [Attributes? attributes]) {
862 : // No-op
863 : }
864 :
865 : /// Records a measurement with attributes as a map (no-op implementation).
866 : ///
867 : /// @param value The measurement value (ignored)
868 : /// @param attributeMap Map of attribute names to values (ignored)
869 1 : @override
870 : void recordWithMap(T value, Map<String, Object> attributeMap) {
871 : // No-op
872 : }
873 :
874 1 : @override
875 : bool get isCounter => false;
876 :
877 1 : @override
878 : bool get isGauge => true;
879 :
880 1 : @override
881 : bool get isHistogram => false;
882 :
883 1 : @override
884 : bool get isUpDownCounter => false;
885 : }
886 :
887 : /// No-op implementation of ObservableCounter instrument.
888 : ///
889 : /// This implementation conforms to the OpenTelemetry specification for no-op implementations,
890 : /// maintaining the same interface as a functional ObservableCounter but performing no operations.
891 : class NoopObservableCounter<T extends num> implements APIObservableCounter<T> {
892 : @override
893 : final String name;
894 :
895 : @override
896 : final String? description;
897 :
898 : @override
899 : final String? unit;
900 :
901 1 : @override
902 : bool isEnabled() => false;
903 :
904 : @override
905 : final APIMeter meter;
906 :
907 : @override
908 : final InstrumentAdvisory? advisory;
909 :
910 : final List<ObservableCallback<T>> _callbacks = [];
911 :
912 : /// Creates a new NoopObservableCounter with the specified name, unit, description, and callbacks.
913 : ///
914 : /// @param name The name of the instrument
915 : /// @param unit Optional unit of measurement
916 : /// @param description Optional description of what the instrument measures
917 : /// @param advisory Optional advisory parameters
918 : /// @param callbacks Callback functions that will be called when measurements are collected
919 2 : NoopObservableCounter({
920 : required this.name,
921 : this.unit,
922 : this.description,
923 : this.advisory,
924 : List<ObservableCallback<T>> callbacks = const [],
925 2 : }) : meter = NoopMeter(name: 'noop-meter') {
926 2 : for (final callback in callbacks) {
927 0 : addCallback(callback);
928 : }
929 : }
930 :
931 : /// Gets all registered callbacks.
932 : ///
933 : /// @return An unmodifiable list of registered callbacks
934 1 : @override
935 2 : List<ObservableCallback<T>> get callbacks => List.unmodifiable(_callbacks);
936 :
937 : /// Registers a callback function for collecting measurements.
938 : ///
939 : /// @param callback The callback function to register
940 : /// @return A registration object that can be used to unregister the callback
941 1 : @override
942 : APICallbackRegistration<T> addCallback(ObservableCallback<T> callback) {
943 2 : _callbacks.add(callback);
944 1 : return _NoopCallbackRegistration<T>(this, callback);
945 : }
946 :
947 : /// Unregisters a previously registered callback function.
948 : ///
949 : /// @param callback The callback function to unregister
950 1 : @override
951 : void removeCallback(ObservableCallback<T> callback) {
952 2 : _callbacks.remove(callback);
953 : }
954 :
955 : /// Collects measurements from all registered callbacks (no-op implementation).
956 : ///
957 : /// @return An empty list of measurements
958 2 : @override
959 : List<Measurement> collect() {
960 2 : return <Measurement>[];
961 : }
962 : }
963 :
964 : /// No-op implementation of ObservableUpDownCounter instrument.
965 : ///
966 : /// This implementation conforms to the OpenTelemetry specification for no-op implementations,
967 : /// maintaining the same interface as a functional ObservableUpDownCounter but performing no operations.
968 : class NoopObservableUpDownCounter<T extends num>
969 : implements APIObservableUpDownCounter<T> {
970 : @override
971 : final String name;
972 :
973 : @override
974 : final String? description;
975 :
976 : @override
977 : final String? unit;
978 :
979 1 : @override
980 : bool isEnabled() => false;
981 :
982 : @override
983 : final APIMeter meter;
984 :
985 : @override
986 : final InstrumentAdvisory? advisory;
987 :
988 : final List<ObservableCallback<T>> _callbacks = [];
989 :
990 : /// Creates a new NoopObservableUpDownCounter with the specified name, unit, description, and callbacks.
991 : ///
992 : /// @param name The name of the instrument
993 : /// @param unit Optional unit of measurement
994 : /// @param description Optional description of what the instrument measures
995 : /// @param advisory Optional advisory parameters
996 : /// @param callbacks Callback functions that will be called when measurements are collected
997 2 : NoopObservableUpDownCounter({
998 : required this.name,
999 : this.unit,
1000 : this.description,
1001 : this.advisory,
1002 : List<ObservableCallback<T>> callbacks = const [],
1003 2 : }) : meter = NoopMeter(name: 'noop-meter') {
1004 2 : for (final callback in callbacks) {
1005 0 : addCallback(callback);
1006 : }
1007 : }
1008 :
1009 : /// Gets all registered callbacks.
1010 : ///
1011 : /// @return An unmodifiable list of registered callbacks
1012 1 : @override
1013 2 : List<ObservableCallback<T>> get callbacks => List.unmodifiable(_callbacks);
1014 :
1015 : /// Registers a callback function for collecting measurements.
1016 : ///
1017 : /// @param callback The callback function to register
1018 : /// @return A registration object that can be used to unregister the callback
1019 1 : @override
1020 : APICallbackRegistration<T> addCallback(ObservableCallback<T> callback) {
1021 2 : _callbacks.add(callback);
1022 1 : return _NoopCallbackRegistration<T>(this, callback);
1023 : }
1024 :
1025 : /// Unregisters a previously registered callback function.
1026 : ///
1027 : /// @param callback The callback function to unregister
1028 1 : @override
1029 : void removeCallback(ObservableCallback<T> callback) {
1030 2 : _callbacks.remove(callback);
1031 : }
1032 :
1033 : /// Collects measurements from all registered callbacks (no-op implementation).
1034 : ///
1035 : /// @return An empty list of measurements
1036 2 : @override
1037 : List<Measurement> collect() {
1038 2 : return <Measurement>[];
1039 : }
1040 : }
1041 :
1042 : /// No-op implementation of ObservableGauge instrument.
1043 : ///
1044 : /// This implementation conforms to the OpenTelemetry specification for no-op implementations,
1045 : /// maintaining the same interface as a functional ObservableGauge but performing no operations.
1046 : class NoopObservableGauge<T extends num> implements APIObservableGauge<T> {
1047 : @override
1048 : final String name;
1049 :
1050 : @override
1051 : final String? description;
1052 :
1053 : @override
1054 : final String? unit;
1055 :
1056 1 : @override
1057 : bool isEnabled() => false;
1058 :
1059 : @override
1060 : final APIMeter meter;
1061 :
1062 : @override
1063 : final InstrumentAdvisory? advisory;
1064 :
1065 : final List<ObservableCallback<T>> _callbacks = [];
1066 :
1067 : /// Creates a new NoopObservableGauge with the specified name, unit, description, and callbacks.
1068 : ///
1069 : /// @param name The name of the instrument
1070 : /// @param unit Optional unit of measurement
1071 : /// @param description Optional description of what the instrument measures
1072 : /// @param advisory Optional advisory parameters
1073 : /// @param callbacks Callback functions that will be called when measurements are collected
1074 3 : NoopObservableGauge({
1075 : required this.name,
1076 : this.unit,
1077 : this.description,
1078 : this.advisory,
1079 : List<ObservableCallback<T>> callbacks = const [],
1080 3 : }) : meter = NoopMeter(name: 'noop-meter') {
1081 4 : for (final callback in callbacks) {
1082 1 : addCallback(callback);
1083 : }
1084 : }
1085 :
1086 : /// Gets all registered callbacks.
1087 : ///
1088 : /// @return An unmodifiable list of registered callbacks
1089 2 : @override
1090 4 : List<ObservableCallback<T>> get callbacks => List.unmodifiable(_callbacks);
1091 :
1092 : /// Registers a callback function for collecting measurements.
1093 : ///
1094 : /// @param callback The callback function to register
1095 : /// @return A registration object that can be used to unregister the callback
1096 2 : @override
1097 : APICallbackRegistration<T> addCallback(ObservableCallback<T> callback) {
1098 4 : _callbacks.add(callback);
1099 2 : return _NoopCallbackRegistration<T>(this, callback);
1100 : }
1101 :
1102 : /// Unregisters a previously registered callback function.
1103 : ///
1104 : /// @param callback The callback function to unregister
1105 1 : @override
1106 : void removeCallback(ObservableCallback<T> callback) {
1107 2 : _callbacks.remove(callback);
1108 : }
1109 :
1110 : /// Collects measurements from all registered callbacks (no-op implementation).
1111 : ///
1112 : /// @return An empty list of measurements
1113 2 : @override
1114 : List<Measurement> collect() {
1115 2 : return <Measurement>[];
1116 : }
1117 : }
1118 :
1119 : /// No-op implementation of callback registration for observable instruments.
1120 : ///
1121 : /// This implementation allows unregistering callbacks from no-op instruments.
1122 : class _NoopCallbackRegistration<T extends num>
1123 : implements APICallbackRegistration<T> {
1124 : final dynamic _instrument;
1125 : final ObservableCallback<T> _callback;
1126 :
1127 : /// Creates a new NoopCallbackRegistration.
1128 : ///
1129 : /// @param instrument The instrument that owns the callback
1130 : /// @param callback The callback function to be unregistered
1131 2 : _NoopCallbackRegistration(this._instrument, this._callback);
1132 :
1133 : /// Unregisters the callback from the instrument.
1134 1 : @override
1135 : void unregister() {
1136 2 : if (_instrument is APIObservableCounter<T>) {
1137 3 : (_instrument as APIObservableCounter<T>).removeCallback(_callback);
1138 2 : } else if (_instrument is APIObservableUpDownCounter<T>) {
1139 3 : (_instrument as APIObservableUpDownCounter<T>).removeCallback(_callback);
1140 2 : } else if (_instrument is APIObservableGauge<T>) {
1141 3 : (_instrument as APIObservableGauge<T>).removeCallback(_callback);
1142 : }
1143 : }
1144 : }
|