scuffle_metrics/
collector.rs

1use std::borrow::Cow;
2
3use opentelemetry::KeyValue;
4
5/// A helper trait to force the compiler to check that the collector is valid.
6#[doc(hidden)]
7pub trait IsCollector: private::Sealed {
8    type Builder<'a>;
9
10    fn builder(meter: &opentelemetry::metrics::Meter, name: impl Into<Cow<'static, str>>) -> Self::Builder<'_>;
11}
12
13mod private {
14    pub trait Sealed {
15        type Value;
16    }
17}
18
19macro_rules! impl_collector {
20    ($t:ty, $value:ty, $func:ident, $builder:ty) => {
21        impl private::Sealed for $t {
22            type Value = $value;
23        }
24
25        impl IsCollector for $t {
26            type Builder<'a> = $builder;
27
28            fn builder(meter: &opentelemetry::metrics::Meter, name: impl Into<Cow<'static, str>>) -> Self::Builder<'_> {
29                meter.$func(name)
30            }
31        }
32    };
33}
34
35/// A counter metric. Alias for `opentelemetry::metrics::Counter<T>`.
36///
37/// Counter metrics are used to record a value that can only increase.
38pub type Counter<T> = opentelemetry::metrics::Counter<T>;
39
40/// A counter metric with a `f64` value.
41///
42/// Counter metrics are used to record a value that can only increase.
43pub type CounterF64 = Counter<f64>;
44
45/// A counter metric with a `u64` value.
46///
47/// Counter metrics are used to record a value that can only increase.
48pub type CounterU64 = Counter<u64>;
49
50impl_collector!(
51    CounterF64,
52    f64,
53    f64_counter,
54    opentelemetry::metrics::InstrumentBuilder<'a, CounterF64>
55);
56impl_collector!(
57    CounterU64,
58    u64,
59    u64_counter,
60    opentelemetry::metrics::InstrumentBuilder<'a, CounterU64>
61);
62
63/// A gauge metric. Alias for `opentelemetry::metrics::Gauge<T>`.
64/// Gauge metrics are used to record a value at the current time, and are not
65/// aggregated. If you need to record a value that can be aggregated, use a
66/// `Counter` or `UpDownCounter` instead.
67pub type Gauge<T> = opentelemetry::metrics::Gauge<T>;
68
69/// A gauge metric with a `f64` value.
70///
71/// Gauge metrics are used to record a value at the current time, and are not
72/// aggregated. If you need to record a value that can be aggregated, use a
73/// `Counter` or `UpDownCounter` instead.
74pub type GaugeF64 = Gauge<f64>;
75
76/// A gauge metric with a `i64` value.
77///
78/// Gauge metrics are used to record a value at the current time, and are not
79/// aggregated. If you need to record a value that can be aggregated, use a
80/// `Counter` or `UpDownCounter` instead.
81pub type GaugeI64 = Gauge<i64>;
82
83/// A gauge metric with a `u64` value.
84///
85/// Gauge metrics are used to record a value at the current time, and are not
86/// aggregated. If you need to record a value that can be aggregated, use a
87/// `Counter` or `UpDownCounter` instead.
88pub type GaugeU64 = Gauge<u64>;
89
90impl_collector!(
91    GaugeF64,
92    f64,
93    f64_gauge,
94    opentelemetry::metrics::InstrumentBuilder<'a, GaugeF64>
95);
96impl_collector!(
97    GaugeI64,
98    i64,
99    i64_gauge,
100    opentelemetry::metrics::InstrumentBuilder<'a, GaugeI64>
101);
102impl_collector!(
103    GaugeU64,
104    u64,
105    u64_gauge,
106    opentelemetry::metrics::InstrumentBuilder<'a, GaugeU64>
107);
108
109/// A histogram metric. Alias for `opentelemetry::metrics::Histogram<T>`.
110///
111/// Histograms are used to record a distribution of values.
112pub type Histogram<T> = opentelemetry::metrics::Histogram<T>;
113
114/// A histogram metric with a `f64` value.
115///
116/// Histograms are used to record a distribution of values.
117pub type HistogramF64 = Histogram<f64>;
118
119/// A histogram metric with a `u64` value.
120///
121/// Histograms are used to record a distribution of values.
122pub type HistogramU64 = Histogram<u64>;
123
124impl private::Sealed for HistogramF64 {
125    type Value = f64;
126}
127
128/// Default boundaries for a histogram in Golang.
129const DEFAULT_BOUNDARIES: [f64; 11] = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0];
130
131impl IsCollector for HistogramF64 {
132    type Builder<'a> = opentelemetry::metrics::HistogramBuilder<'a, HistogramF64>;
133
134    fn builder(meter: &opentelemetry::metrics::Meter, name: impl Into<Cow<'static, str>>) -> Self::Builder<'_> {
135        meter.f64_histogram(name).with_boundaries(DEFAULT_BOUNDARIES.into())
136    }
137}
138
139impl private::Sealed for HistogramU64 {
140    type Value = u64;
141}
142
143impl IsCollector for HistogramU64 {
144    type Builder<'a> = opentelemetry::metrics::HistogramBuilder<'a, HistogramU64>;
145
146    fn builder(meter: &opentelemetry::metrics::Meter, name: impl Into<Cow<'static, str>>) -> Self::Builder<'_> {
147        meter.u64_histogram(name).with_boundaries(DEFAULT_BOUNDARIES.into())
148    }
149}
150
151/// A updown counter metric. Alias for
152/// `opentelemetry::metrics::UpDownCounter<T>`.
153///
154/// UpDownCounter like the `Counter` metric, but can also decrement.
155pub type UpDownCounter<T> = opentelemetry::metrics::UpDownCounter<T>;
156
157/// A updown counter metric with a `i64` value.
158///
159/// UpDownCounter like the `Counter` metric, but can also decrement.
160pub type UpDownCounterI64 = UpDownCounter<i64>;
161
162/// A updown counter metric with a `f64` value.
163///
164/// UpDownCounter like the `Counter` metric, but can also decrement.
165pub type UpDownCounterF64 = UpDownCounter<f64>;
166
167impl_collector!(
168    UpDownCounterI64,
169    i64,
170    i64_up_down_counter,
171    opentelemetry::metrics::InstrumentBuilder<'a, UpDownCounterI64>
172);
173impl_collector!(
174    UpDownCounterF64,
175    f64,
176    f64_up_down_counter,
177    opentelemetry::metrics::InstrumentBuilder<'a, UpDownCounterF64>
178);
179
180/// Helper trait to get a value of one for a number type.
181/// Used by the macros below to increment and decrement counters.
182trait Number {
183    const ONE: Self;
184}
185
186impl Number for f64 {
187    const ONE: Self = 1.0;
188}
189
190impl Number for u64 {
191    const ONE: Self = 1;
192}
193
194impl Number for i64 {
195    const ONE: Self = 1;
196}
197
198/// A collector is a wrapper around a metric with some attributes.
199///
200/// Please use the [`#[metrics]`](crate::metrics) macro to create collectors.
201#[must_use = "Collectors do nothing by themselves, you must call them"]
202pub struct Collector<'a, T: IsCollector> {
203    attributes: Vec<KeyValue>,
204    collector: &'a T,
205}
206
207impl<'a, T: IsCollector> Collector<'a, T> {
208    /// Wraps a given collector with the provided attributes.
209    ///
210    /// This is typically used internally for constructing types
211    /// when using the [`#[metrics]`](crate::metrics) module or function attribute.
212    pub fn new(attributes: Vec<KeyValue>, collector: &'a T) -> Self {
213        Self { attributes, collector }
214    }
215
216    /// Returns the inner collector.
217    pub fn inner(&self) -> &'a T {
218        self.collector
219    }
220}
221
222macro_rules! impl_counter {
223    ($t:ty) => {
224        impl<'a> Collector<'a, opentelemetry::metrics::Counter<$t>> {
225            /// Increments the counter by one.
226            #[inline]
227            pub fn incr(&self) {
228                self.incr_by(<$t as Number>::ONE);
229            }
230
231            /// Increments the counter by the given value.
232            pub fn incr_by(&self, value: $t) {
233                self.collector.add(value, &self.attributes);
234            }
235        }
236    };
237}
238
239impl_counter!(u64);
240impl_counter!(f64);
241
242macro_rules! impl_gauge {
243    ($t:ty) => {
244        impl<'a> Collector<'a, opentelemetry::metrics::Gauge<$t>> {
245            /// Sets the value of the gauge.
246            pub fn record(&self, value: $t) {
247                self.collector.record(value, &self.attributes);
248            }
249        }
250    };
251}
252
253impl_gauge!(u64);
254impl_gauge!(f64);
255impl_gauge!(i64);
256
257macro_rules! impl_histogram {
258    ($t:ty) => {
259        impl<'a> Collector<'a, opentelemetry::metrics::Histogram<$t>> {
260            /// Observes a new value.
261            pub fn observe(&self, value: $t) {
262                self.collector.record(value, &self.attributes);
263            }
264        }
265    };
266}
267
268impl_histogram!(u64);
269impl_histogram!(f64);
270
271macro_rules! impl_updowncounter {
272    ($t:ty) => {
273        impl<'a> Collector<'a, opentelemetry::metrics::UpDownCounter<$t>> {
274            /// Increments the counter by one.
275            pub fn incr(&self) {
276                self.incr_by(<$t as Number>::ONE);
277            }
278
279            /// Increments the counter by the given value.
280            pub fn incr_by(&self, value: $t) {
281                self.collector.add(value, &self.attributes);
282            }
283
284            /// Decrements the counter by one.
285            pub fn decr(&self) {
286                self.decr_by(<$t as Number>::ONE);
287            }
288
289            /// Decrements the counter by the given value.
290            pub fn decr_by(&self, value: $t) {
291                self.collector.add(-value, &self.attributes);
292            }
293        }
294    };
295}
296
297impl_updowncounter!(i64);
298impl_updowncounter!(f64);