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/histogram_storage.dart';
10 : import 'base_instrument.dart';
11 :
12 : /// Histogram is a synchronous instrument that records a distribution of values.
13 : ///
14 : /// A Histogram is used to measure a distribution of values, such as request durations,
15 : /// response sizes, or latencies.
16 : class Histogram<T extends num> implements APIHistogram<T>, SDKInstrument {
17 : /// The underlying API Histogram.
18 : final APIHistogram<T> _apiHistogram;
19 :
20 : /// The Meter that created this Histogram.
21 : final Meter _meter;
22 :
23 : /// Storage for accumulating histogram measurements.
24 : final HistogramStorage<T> _storage;
25 :
26 : /// Creates a new Histogram instance.
27 : ///
28 : /// Bucket boundaries come from [boundaries] when given, otherwise from
29 : /// the instrument's [InstrumentAdvisory.explicitBucketBoundaries], and
30 : /// otherwise from the spec's default buckets.
31 8 : Histogram({
32 : required APIHistogram<T> apiHistogram,
33 : required Meter meter,
34 : List<double>? boundaries,
35 : }) : _apiHistogram = apiHistogram,
36 : _meter = meter,
37 8 : _storage = HistogramStorage(
38 : boundaries: boundaries ??
39 12 : apiHistogram.advisory?.explicitBucketBoundaries ??
40 : _defaultBoundaries,
41 : recordMinMax: true,
42 16 : exemplarFilter: meter.provider.exemplarFilter,
43 : ) {
44 : // Register this instrument with the meter provider
45 40 : _meter.provider.registerInstrument(_meter.name, this);
46 : }
47 :
48 : /// Default bucket boundaries.
49 : static const List<double> _defaultBoundaries = [
50 : 0,
51 : 5,
52 : 10,
53 : 25,
54 : 50,
55 : 75,
56 : 100,
57 : 250,
58 : 500,
59 : 750,
60 : 1000,
61 : 2500,
62 : 5000,
63 : 7500,
64 : 10000,
65 : ];
66 :
67 8 : @override
68 16 : String get name => _apiHistogram.name;
69 :
70 3 : @override
71 6 : String? get unit => _apiHistogram.unit;
72 :
73 3 : @override
74 6 : String? get description => _apiHistogram.description;
75 :
76 5 : @override
77 10 : bool isEnabled() => _meter.isEnabled();
78 :
79 8 : @override
80 8 : APIMeter get meter => _meter;
81 :
82 2 : @override
83 4 : InstrumentAdvisory? get advisory => _apiHistogram.advisory;
84 :
85 0 : @Deprecated('Use advisory?.explicitBucketBoundaries instead')
86 : @override
87 0 : List<double>? get boundaries => advisory?.explicitBucketBoundaries;
88 :
89 1 : @override
90 : bool get isCounter => false;
91 :
92 1 : @override
93 : bool get isUpDownCounter => false;
94 :
95 1 : @override
96 : bool get isGauge => false;
97 :
98 1 : @override
99 : bool get isHistogram => true;
100 :
101 5 : @override
102 : void record(T value, [Attributes? attributes]) {
103 : // First use the API implementation (no-op by default)
104 10 : _apiHistogram.record(value, attributes);
105 :
106 : // Only record if enabled
107 5 : if (!isEnabled()) return;
108 :
109 : // Record the measurement in our storage
110 15 : _storage.record(value, attributes, Context.current);
111 : }
112 :
113 1 : @override
114 : void recordWithMap(T value, Map<String, Object> attributeMap) {
115 : // Just convert to Attributes and call record
116 : final attributes =
117 2 : attributeMap.isEmpty ? null : attributeMap.toAttributes();
118 1 : record(value, attributes);
119 : }
120 :
121 : /// Gets the current histogram value for the given attributes.
122 : /// If no attributes are provided, returns the histogram value for the null/empty attribute set.
123 3 : HistogramValue getValue([Attributes? attributes]) {
124 6 : return _storage.getValue(attributes);
125 : }
126 :
127 : /// Gets the current points for this histogram.
128 : /// This is used by the SDK to collect metrics.
129 3 : List<MetricPoint<HistogramValue>> collectPoints() {
130 6 : return _storage.collectPoints();
131 : }
132 :
133 3 : @override
134 : List<Metric> collectMetrics() {
135 4 : if (!isEnabled()) return [];
136 :
137 : // Get the points from storage
138 3 : final points = collectPoints();
139 :
140 3 : if (points.isEmpty) return [];
141 :
142 : // Create a metric with the collected points
143 3 : final metric = Metric(
144 3 : name: name,
145 3 : description: description,
146 3 : unit: unit,
147 : type: MetricType.histogram,
148 : points: points,
149 : );
150 :
151 3 : return [metric];
152 : }
153 :
154 : /// Resets the histogram. This is only used for Delta temporality.
155 1 : void reset() {
156 2 : _storage.reset();
157 : }
158 : }
|