saluki_core/data_model/event/metric/
mod.rs

1//! Metric types.
2
3mod metadata;
4use std::time::Duration;
5
6use saluki_context::Context;
7
8pub use self::metadata::*;
9
10mod value;
11pub use self::value::{
12    Histogram, HistogramPoints, HistogramSummary, MetricValues, ScalarPoints, SetPoints, SketchPoints,
13};
14
15/// A metric.
16///
17/// Metrics represent the measurement of a particular quantity at a particular point in time. Several different metric
18/// types exist that provide different views into the underlying quantity: counters for representing the quantities that
19/// are aggregated/totaled over time, gauges for tracking the latest value of a quantity, and histograms for tracking
20/// the distribution of a quantity.
21///
22/// ## Structure
23///
24/// A metric is composed of three parts: the context, the value, and the metadata.
25///
26/// The context represents the "full" name of the metric, which includes not only the name (e.g. `http_requests_total`),
27/// but the tags as well. Effectively, a context is meant to be a unique name for a metric.
28///
29/// The value is precisely what it sounds like: the value of the metric. The value holds both the metric type and the
30/// measurement (or measurements) tied to that metric type. This ensures that the measurement(s) are always represented
31/// correctly for the given metric type.
32///
33/// The metadata contains ancillary data related to the metric, such as the timestamp, sample rate, and origination
34/// information like hostname and sender.
35#[derive(Clone, Debug, PartialEq)]
36pub struct Metric {
37    context: Context,
38    values: MetricValues,
39    metadata: MetricMetadata,
40}
41
42impl Metric {
43    /// Creates a counter metric from the given context and value(s).
44    ///
45    /// Default metadata will be used.
46    pub fn counter<C, V>(context: C, values: V) -> Self
47    where
48        C: Into<Context>,
49        V: Into<ScalarPoints>,
50    {
51        Self {
52            context: context.into(),
53            values: MetricValues::counter(values),
54            metadata: MetricMetadata::default(),
55        }
56    }
57
58    /// Creates a gauge metric from the given context and value(s).
59    ///
60    /// Default metadata will be used.
61    pub fn gauge<C, V>(context: C, values: V) -> Self
62    where
63        C: Into<Context>,
64        V: Into<ScalarPoints>,
65    {
66        Self {
67            context: context.into(),
68            values: MetricValues::gauge(values),
69            metadata: MetricMetadata::default(),
70        }
71    }
72
73    /// Creates a rate metric from the given context and value(s).
74    ///
75    /// Default metadata will be used.
76    pub fn rate<C, V>(context: C, values: V, interval: Duration) -> Self
77    where
78        C: Into<Context>,
79        V: Into<ScalarPoints>,
80    {
81        Self {
82            context: context.into(),
83            values: MetricValues::rate(values, interval),
84            metadata: MetricMetadata::default(),
85        }
86    }
87
88    /// Creates a set metric from the given context and value(s).
89    ///
90    /// Default metadata will be used.
91    pub fn set<C, V>(context: C, values: V) -> Self
92    where
93        C: Into<Context>,
94        V: Into<SetPoints>,
95    {
96        Self {
97            context: context.into(),
98            values: MetricValues::set(values),
99            metadata: MetricMetadata::default(),
100        }
101    }
102
103    /// Creates a histogram metric from the given context and value(s).
104    ///
105    /// Default metadata will be used.
106    pub fn histogram<C, V>(context: C, values: V) -> Self
107    where
108        C: Into<Context>,
109        V: Into<HistogramPoints>,
110    {
111        Self {
112            context: context.into(),
113            values: MetricValues::histogram(values),
114            metadata: MetricMetadata::default(),
115        }
116    }
117
118    /// Creates a distribution metric from the given context and value(s).
119    ///
120    /// Default metadata will be used.
121    pub fn distribution<C, V>(context: C, values: V) -> Self
122    where
123        C: Into<Context>,
124        V: Into<SketchPoints>,
125    {
126        Self {
127            context: context.into(),
128            values: MetricValues::distribution(values),
129            metadata: MetricMetadata::default(),
130        }
131    }
132
133    /// Gets a reference to the context.
134    pub fn context(&self) -> &Context {
135        &self.context
136    }
137
138    /// Gets a mutable reference to the context.
139    pub fn context_mut(&mut self) -> &mut Context {
140        &mut self.context
141    }
142
143    /// Gets a reference to the values.
144    pub fn values(&self) -> &MetricValues {
145        &self.values
146    }
147
148    /// Gets a mutable reference to the values.
149    pub fn values_mut(&mut self) -> &mut MetricValues {
150        &mut self.values
151    }
152
153    /// Gets a reference to the metadata.
154    pub fn metadata(&self) -> &MetricMetadata {
155        &self.metadata
156    }
157
158    /// Gets a mutable reference to the metadata.
159    pub fn metadata_mut(&mut self) -> &mut MetricMetadata {
160        &mut self.metadata
161    }
162
163    /// Consumes the metric and returns the individual parts.
164    pub fn into_parts(self) -> (Context, MetricValues, MetricMetadata) {
165        (self.context, self.values, self.metadata)
166    }
167
168    /// Creates a `Metric` from the given parts.
169    pub fn from_parts(context: Context, values: MetricValues, metadata: MetricMetadata) -> Self {
170        Self {
171            context,
172            values,
173            metadata,
174        }
175    }
176}
177
178/// A sample rate.
179///
180/// Sample rates are used to indicate the rate at which a metric was sampled, and are represented by a value between 0.0
181/// and 1.0 (inclusive). For example, when handling a value with a sample rate of 0.25, this indicates the value is only
182/// being sent 25% of the time. This means it has a "weight" of 4: this single value should be considered to represent
183/// 4 actual samples with the same value.
184#[derive(Clone, Copy)]
185pub struct SampleRate(f64);
186
187impl SampleRate {
188    /// Creates a new sample rate indicating the metric was unsampled.
189    pub const fn unsampled() -> Self {
190        Self(1.0)
191    }
192
193    /// Returns the weight of the sample rate.
194    pub fn weight(&self) -> u64 {
195        (1.0 / self.0) as u64
196    }
197
198    /// Returns the weight of the sample rate as a raw floating-point value.
199    pub fn raw_weight(&self) -> f64 {
200        1.0 / self.0
201    }
202}
203
204impl TryFrom<f64> for SampleRate {
205    type Error = &'static str;
206
207    fn try_from(value: f64) -> Result<Self, Self::Error> {
208        if !(0.0..=1.0).contains(&value) {
209            Err("sample rate must be between 0.0 and 1.0")
210        } else {
211            Ok(Self(value))
212        }
213    }
214}