opentelemetry_sdk/metrics/
instrument.rs1use std::{borrow::Cow, collections::HashSet, sync::Arc};
2
3use opentelemetry::{
4 metrics::{AsyncInstrument, SyncInstrument},
5 InstrumentationScope, Key, KeyValue,
6};
7
8use crate::metrics::{aggregation::Aggregation, internal::Measure};
9
10use super::Temporality;
11
12#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
14pub enum InstrumentKind {
15 Counter,
18 UpDownCounter,
21 Histogram,
24 ObservableCounter,
27 ObservableUpDownCounter,
30
31 Gauge,
34 ObservableGauge,
37}
38
39impl InstrumentKind {
40 pub(crate) fn temporality_preference(&self, temporality: Temporality) -> Temporality {
44 match temporality {
45 Temporality::Cumulative => Temporality::Cumulative,
46 Temporality::Delta => match self {
47 Self::Counter
48 | Self::Histogram
49 | Self::ObservableCounter
50 | Self::Gauge
51 | Self::ObservableGauge => Temporality::Delta,
52 Self::UpDownCounter | InstrumentKind::ObservableUpDownCounter => {
53 Temporality::Cumulative
54 }
55 },
56 Temporality::LowMemory => match self {
57 Self::Counter | InstrumentKind::Histogram => Temporality::Delta,
58 Self::ObservableCounter
59 | Self::Gauge
60 | Self::ObservableGauge
61 | Self::UpDownCounter
62 | Self::ObservableUpDownCounter => Temporality::Cumulative,
63 },
64 }
65 }
66}
67
68#[derive(Clone, Default, Debug, PartialEq)]
85#[non_exhaustive]
86#[allow(unreachable_pub)]
87pub struct Instrument {
88 pub name: Cow<'static, str>,
90 pub description: Cow<'static, str>,
92 pub kind: Option<InstrumentKind>,
94 pub unit: Cow<'static, str>,
96 pub scope: InstrumentationScope,
98}
99
100#[cfg(feature = "spec_unstable_metrics_views")]
101impl Instrument {
102 pub fn new() -> Self {
104 Instrument::default()
105 }
106
107 pub fn name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
109 self.name = name.into();
110 self
111 }
112
113 pub fn description(mut self, description: impl Into<Cow<'static, str>>) -> Self {
115 self.description = description.into();
116 self
117 }
118
119 pub fn unit(mut self, unit: impl Into<Cow<'static, str>>) -> Self {
121 self.unit = unit.into();
122 self
123 }
124
125 pub fn scope(mut self, scope: InstrumentationScope) -> Self {
127 self.scope = scope;
128 self
129 }
130
131 pub(crate) fn is_empty(&self) -> bool {
133 self.name == ""
134 && self.description == ""
135 && self.kind.is_none()
136 && self.unit == ""
137 && self.scope == InstrumentationScope::default()
138 }
139
140 pub(crate) fn matches(&self, other: &Instrument) -> bool {
141 self.matches_name(other)
142 && self.matches_description(other)
143 && self.matches_kind(other)
144 && self.matches_unit(other)
145 && self.matches_scope(other)
146 }
147
148 pub(crate) fn matches_name(&self, other: &Instrument) -> bool {
149 self.name.is_empty() || self.name.as_ref() == other.name.as_ref()
150 }
151
152 pub(crate) fn matches_description(&self, other: &Instrument) -> bool {
153 self.description.is_empty() || self.description.as_ref() == other.description.as_ref()
154 }
155
156 pub(crate) fn matches_kind(&self, other: &Instrument) -> bool {
157 self.kind.is_none() || self.kind == other.kind
158 }
159
160 pub(crate) fn matches_unit(&self, other: &Instrument) -> bool {
161 self.unit.is_empty() || self.unit.as_ref() == other.unit.as_ref()
162 }
163
164 pub(crate) fn matches_scope(&self, other: &Instrument) -> bool {
165 (self.scope.name().is_empty() || self.scope.name() == other.scope.name())
166 && (self.scope.version().is_none()
167 || self.scope.version().as_ref() == other.scope.version().as_ref())
168 && (self.scope.schema_url().is_none()
169 || self.scope.schema_url().as_ref() == other.scope.schema_url().as_ref())
170 }
171}
172
173#[derive(Default, Debug)]
189#[non_exhaustive]
190#[allow(unreachable_pub)]
191pub struct Stream {
192 pub name: Cow<'static, str>,
194 pub description: Cow<'static, str>,
196 pub unit: Cow<'static, str>,
198 pub aggregation: Option<Aggregation>,
200 pub allowed_attribute_keys: Option<Arc<HashSet<Key>>>,
206}
207
208#[cfg(feature = "spec_unstable_metrics_views")]
209impl Stream {
210 pub fn new() -> Self {
212 Stream::default()
213 }
214
215 pub fn name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
217 self.name = name.into();
218 self
219 }
220
221 pub fn description(mut self, description: impl Into<Cow<'static, str>>) -> Self {
223 self.description = description.into();
224 self
225 }
226
227 pub fn unit(mut self, unit: impl Into<Cow<'static, str>>) -> Self {
229 self.unit = unit.into();
230 self
231 }
232
233 pub fn aggregation(mut self, aggregation: Aggregation) -> Self {
235 self.aggregation = Some(aggregation);
236 self
237 }
238
239 pub fn allowed_attribute_keys(mut self, attribute_keys: impl IntoIterator<Item = Key>) -> Self {
244 self.allowed_attribute_keys = Some(Arc::new(attribute_keys.into_iter().collect()));
245
246 self
247 }
248}
249
250#[derive(Debug, PartialEq, Eq, Hash)]
252pub(crate) struct InstrumentId {
253 pub(crate) name: Cow<'static, str>,
255 pub(crate) description: Cow<'static, str>,
257 pub(crate) kind: InstrumentKind,
259 pub(crate) unit: Cow<'static, str>,
261 pub(crate) number: Cow<'static, str>,
263}
264
265impl InstrumentId {
266 pub(crate) fn normalize(&mut self) {
275 if self.name.chars().any(|c| c.is_ascii_uppercase()) {
276 self.name = self.name.to_ascii_lowercase().into();
277 }
278 }
279}
280
281pub(crate) struct ResolvedMeasures<T> {
282 pub(crate) measures: Vec<Arc<dyn Measure<T>>>,
283}
284
285impl<T: Copy + 'static> SyncInstrument<T> for ResolvedMeasures<T> {
286 fn measure(&self, val: T, attrs: &[KeyValue]) {
287 for measure in &self.measures {
288 measure.call(val, attrs)
289 }
290 }
291}
292
293#[derive(Clone)]
294pub(crate) struct Observable<T> {
295 measures: Vec<Arc<dyn Measure<T>>>,
296}
297
298impl<T> Observable<T> {
299 pub(crate) fn new(measures: Vec<Arc<dyn Measure<T>>>) -> Self {
300 Self { measures }
301 }
302}
303
304impl<T: Copy + Send + Sync + 'static> AsyncInstrument<T> for Observable<T> {
305 fn observe(&self, measurement: T, attrs: &[KeyValue]) {
306 for measure in &self.measures {
307 measure.call(measurement, attrs)
308 }
309 }
310}