Line data Source code
1 : // Licensed under the Apache License, Version 2.0
2 : // Copyright 2025, Michael Bushe, All rights reserved.
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 4 : Histogram({
28 : required APIHistogram<T> apiHistogram,
29 : required Meter meter,
30 : List<double>? boundaries,
31 : }) : _apiHistogram = apiHistogram,
32 : _meter = meter,
33 4 : _storage = HistogramStorage(
34 : boundaries: boundaries ?? _defaultBoundaries,
35 : recordMinMax: true,
36 : ) {
37 : // Register this instrument with the meter provider
38 20 : _meter.provider.registerInstrument(_meter.name, this);
39 : }
40 :
41 : /// Default bucket boundaries.
42 : static const List<double> _defaultBoundaries = [
43 : 0,
44 : 5,
45 : 10,
46 : 25,
47 : 50,
48 : 75,
49 : 100,
50 : 250,
51 : 500,
52 : 750,
53 : 1000,
54 : 2500,
55 : 5000,
56 : 7500,
57 : 10000
58 : ];
59 :
60 4 : @override
61 8 : String get name => _apiHistogram.name;
62 :
63 3 : @override
64 6 : String? get unit => _apiHistogram.unit;
65 :
66 3 : @override
67 6 : String? get description => _apiHistogram.description;
68 :
69 3 : @override
70 6 : bool get enabled => _meter.enabled;
71 :
72 4 : @override
73 4 : APIMeter get meter => _meter;
74 :
75 0 : @override
76 0 : List<double>? get boundaries => _apiHistogram.boundaries;
77 :
78 1 : @override
79 : bool get isCounter => false;
80 :
81 1 : @override
82 : bool get isUpDownCounter => false;
83 :
84 1 : @override
85 : bool get isGauge => false;
86 :
87 1 : @override
88 : bool get isHistogram => true;
89 :
90 3 : @override
91 : void record(T value, [Attributes? attributes]) {
92 : // First use the API implementation (no-op by default)
93 6 : _apiHistogram.record(value, attributes);
94 :
95 : // Only record if enabled
96 3 : if (!enabled) return;
97 :
98 : // Record the measurement in our storage
99 6 : _storage.record(value, attributes);
100 : }
101 :
102 1 : @override
103 : void recordWithMap(T value, Map<String, Object> attributeMap) {
104 : // Just convert to Attributes and call record
105 : final attributes =
106 2 : attributeMap.isEmpty ? null : attributeMap.toAttributes();
107 1 : record(value, attributes);
108 : }
109 :
110 : /// Gets the current histogram value for the given attributes.
111 : /// If no attributes are provided, returns the histogram value for the null/empty attribute set.
112 1 : HistogramValue getValue([Attributes? attributes]) {
113 2 : return _storage.getValue(attributes);
114 : }
115 :
116 : /// Gets the current points for this histogram.
117 : /// This is used by the SDK to collect metrics.
118 3 : List<MetricPoint<HistogramValue>> collectPoints() {
119 6 : return _storage.collectPoints();
120 : }
121 :
122 3 : @override
123 : List<Metric> collectMetrics() {
124 4 : if (!enabled) return [];
125 :
126 : // Get the points from storage
127 3 : final points = collectPoints();
128 :
129 3 : if (points.isEmpty) return [];
130 :
131 : // Create a metric with the collected points
132 3 : final metric = Metric(
133 3 : name: name,
134 3 : description: description,
135 3 : unit: unit,
136 : type: MetricType.histogram,
137 : points: points,
138 : );
139 :
140 3 : return [metric];
141 : }
142 :
143 : /// Resets the histogram. This is only used for Delta temporality.
144 1 : void reset() {
145 2 : _storage.reset();
146 : }
147 : }
|