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}