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 :
6 : import '../data/metric.dart';
7 : import '../data/metric_point.dart';
8 : import '../meter.dart';
9 : import '../storage/sum_storage.dart';
10 : import 'base_instrument.dart';
11 :
12 : /// UpDownCounter is a synchronous instrument that records additive values.
13 : ///
14 : /// An UpDownCounter is used to measure a value that increases and decreases.
15 : /// For example, the number of active requests, queue size, pool size.
16 : class UpDownCounter<T extends num>
17 : implements APIUpDownCounter<T>, SDKInstrument {
18 : /// The underlying API UpDownCounter.
19 : final APIUpDownCounter<T> _apiCounter;
20 :
21 : /// The Meter that created this UpDownCounter.
22 : final Meter _meter;
23 :
24 : /// Storage for accumulating up-down counter measurements.
25 : final SumStorage<T> _storage;
26 :
27 : /// Creates a new UpDownCounter instance.
28 5 : UpDownCounter({required APIUpDownCounter<T> apiCounter, required Meter meter})
29 : : _apiCounter = apiCounter,
30 : _meter = meter,
31 5 : _storage = SumStorage<T>(
32 : isMonotonic: false,
33 10 : exemplarFilter: meter.provider.exemplarFilter,
34 : ) {
35 : // Register this instrument with the meter provider
36 25 : _meter.provider.registerInstrument(_meter.name, this);
37 : }
38 :
39 5 : @override
40 10 : String get name => _apiCounter.name;
41 :
42 2 : @override
43 4 : String? get unit => _apiCounter.unit;
44 :
45 2 : @override
46 4 : String? get description => _apiCounter.description;
47 :
48 1 : @override
49 2 : bool isEnabled() => _meter.isEnabled();
50 :
51 5 : @override
52 5 : APIMeter get meter => _meter;
53 :
54 1 : @override
55 : bool get isCounter => false;
56 :
57 1 : @override
58 : bool get isUpDownCounter => true;
59 :
60 1 : @override
61 : bool get isGauge => false;
62 :
63 1 : @override
64 : bool get isHistogram => false;
65 :
66 3 : @override
67 : void add(T value, [Attributes? attributes]) {
68 : // First use the API implementation (no-op by default)
69 6 : _apiCounter.add(value, attributes);
70 :
71 : // In the SDK, we only check the meter's enabled state
72 6 : if (!_meter.isEnabled()) return;
73 :
74 : // Record the measurement in our storage
75 9 : _storage.record(value, attributes, Context.current);
76 : }
77 :
78 1 : @override
79 : void addWithMap(T value, Map<String, Object> attributeMap) {
80 : // Just convert to Attributes and call add
81 : final attributes =
82 2 : attributeMap.isEmpty ? null : attributeMap.toAttributes();
83 1 : add(value, attributes);
84 : }
85 :
86 : /// Gets the current value of the counter for a specific set of attributes.
87 : /// If no attributes are provided, returns the sum of all values across all attributes.
88 3 : T getValue([Attributes? attributes]) {
89 6 : return _storage.getValue(attributes);
90 : }
91 :
92 : /// Gets the current points for this counter.
93 : /// This is used by the SDK to collect metrics.
94 1 : List<MetricPoint<T>> collectPoints() {
95 2 : return _storage.collectPoints();
96 : }
97 :
98 1 : @override
99 : List<Metric> collectMetrics() {
100 2 : if (!isEnabled()) return [];
101 :
102 : // Get the points from storage
103 1 : final points = collectPoints();
104 :
105 1 : if (points.isEmpty) return [];
106 :
107 : // Create a metric with the collected points
108 1 : final metric = Metric(
109 1 : name: name,
110 1 : description: description,
111 1 : unit: unit,
112 : type: MetricType.sum, // UpDownCounter is still a sum, just not monotonic
113 : points: points,
114 : );
115 :
116 1 : return [metric];
117 : }
118 :
119 : /// Resets the counter. This is only used for Delta temporality.
120 2 : void reset() {
121 4 : _storage.reset();
122 : }
123 : }
|