saluki_core/data_model/event/
mod.rs

1//! Telemetry events.
2
3use std::fmt;
4
5use bitmask_enum::bitmask;
6
7pub mod metric;
8use self::metric::Metric;
9
10pub mod eventd;
11use self::eventd::EventD;
12
13pub mod service_check;
14use self::service_check::ServiceCheck;
15
16pub mod log;
17use self::log::Log;
18
19pub mod trace;
20use self::trace::Trace;
21
22pub mod trace_stats;
23use self::trace_stats::TraceStats;
24
25/// Telemetry event type.
26///
27/// This type is a bitmask, which means different event types can be combined together. This makes `EventType` mainly
28/// useful for defining the type of telemetry events that a component emits, or can handle.
29#[bitmask(u8)]
30#[bitmask_config(vec_debug)]
31pub enum EventType {
32    /// Metrics.
33    Metric,
34
35    /// Datadog Events.
36    EventD,
37
38    /// Service checks.
39    ServiceCheck,
40
41    /// Logs.
42    Log,
43
44    /// Traces.
45    Trace,
46
47    /// Trace stats.
48    TraceStats,
49}
50
51impl Default for EventType {
52    fn default() -> Self {
53        Self::none()
54    }
55}
56
57impl fmt::Display for EventType {
58    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59        let mut types = Vec::new();
60
61        if self.contains(Self::Metric) {
62            types.push("Metric");
63        }
64
65        if self.contains(Self::EventD) {
66            types.push("DatadogEvent");
67        }
68
69        if self.contains(Self::ServiceCheck) {
70            types.push("ServiceCheck");
71        }
72
73        if self.contains(Self::Log) {
74            types.push("Log");
75        }
76
77        if self.contains(Self::Trace) {
78            types.push("Trace");
79        }
80
81        if self.contains(Self::TraceStats) {
82            types.push("TraceStats");
83        }
84
85        write!(f, "{}", types.join("|"))
86    }
87}
88
89/// A telemetry event.
90#[derive(Clone, Debug, PartialEq)]
91pub enum Event {
92    /// A metric.
93    Metric(Metric),
94
95    /// A Datadog Event.
96    EventD(EventD),
97
98    /// A service check.
99    ServiceCheck(ServiceCheck),
100
101    /// A log.
102    Log(Log),
103
104    /// A trace.
105    Trace(Trace),
106
107    /// Trace stats.
108    TraceStats(TraceStats),
109}
110
111impl Event {
112    /// Gets the type of this event.
113    pub fn event_type(&self) -> EventType {
114        match self {
115            Event::Metric(_) => EventType::Metric,
116            Event::EventD(_) => EventType::EventD,
117            Event::ServiceCheck(_) => EventType::ServiceCheck,
118            Event::Log(_) => EventType::Log,
119            Event::Trace(_) => EventType::Trace,
120            Event::TraceStats(_) => EventType::TraceStats,
121        }
122    }
123
124    /// Returns the inner event value, if this event is a `Metric`.
125    ///
126    /// Otherwise, `None` is returned and the original event is consumed.
127    pub fn try_into_metric(self) -> Option<Metric> {
128        match self {
129            Event::Metric(metric) => Some(metric),
130            _ => None,
131        }
132    }
133
134    /// Returns a reference inner event value, if this event is a `Metric`.
135    ///
136    /// Otherwise, `None` is returned.
137    pub fn try_as_metric(&self) -> Option<&Metric> {
138        match self {
139            Event::Metric(metric) => Some(metric),
140            _ => None,
141        }
142    }
143
144    /// Returns a mutable reference inner event value, if this event is a `Metric`.
145    ///
146    /// Otherwise, `None` is returned.
147    pub fn try_as_metric_mut(&mut self) -> Option<&mut Metric> {
148        match self {
149            Event::Metric(metric) => Some(metric),
150            _ => None,
151        }
152    }
153
154    /// Returns a mutable reference to the inner event value, if this event is an `EventD`.
155    ///
156    /// Otherwise, `None` is returned.
157    pub fn try_as_eventd_mut(&mut self) -> Option<&mut EventD> {
158        match self {
159            Event::EventD(eventd) => Some(eventd),
160            _ => None,
161        }
162    }
163
164    /// Returns the inner event value, if this event is an `EventD`.
165    ///
166    /// Otherwise, `None` is returned and the original event is consumed.
167    pub fn try_into_eventd(self) -> Option<EventD> {
168        match self {
169            Event::EventD(eventd) => Some(eventd),
170            _ => None,
171        }
172    }
173
174    /// Returns the inner event value, if this event is a `ServiceCheck`.
175    ///
176    /// Otherwise, `None` is returned and the original event is consumed.
177    pub fn try_into_service_check(self) -> Option<ServiceCheck> {
178        match self {
179            Event::ServiceCheck(service_check) => Some(service_check),
180            _ => None,
181        }
182    }
183
184    /// Returns a mutable reference to the inner event value, if this event is a `ServiceCheck`.
185    ///
186    /// Otherwise, `None` is returned.
187    pub fn try_as_service_check_mut(&mut self) -> Option<&mut ServiceCheck> {
188        match self {
189            Event::ServiceCheck(service_check) => Some(service_check),
190            _ => None,
191        }
192    }
193
194    /// Returns a reference inner event value, if this event is a `Trace`.
195    ///
196    /// Otherwise, `None` is returned.
197    pub fn try_into_trace(self) -> Option<Trace> {
198        match self {
199            Event::Trace(trace) => Some(trace),
200            _ => None,
201        }
202    }
203
204    /// Returns a mutable reference inner event value, if this event is a `Trace`.
205    ///
206    /// Otherwise, `None` is returned.
207    pub fn try_as_trace_mut(&mut self) -> Option<&mut Trace> {
208        match self {
209            Event::Trace(trace) => Some(trace),
210            _ => None,
211        }
212    }
213
214    /// Returns the inner event value, if this event is a `TraceStats`.
215    ///
216    /// Otherwise, `None` is returned and the original event is consumed.
217    pub fn try_into_trace_stats(self) -> Option<TraceStats> {
218        match self {
219            Event::TraceStats(stats) => Some(stats),
220            _ => None,
221        }
222    }
223
224    #[allow(unused)]
225    /// Returns `true` if the event is a `Metric`.
226    pub fn is_metric(&self) -> bool {
227        matches!(self, Event::Metric(_))
228    }
229
230    /// Returns `true` if the event is an `EventD`.
231    pub fn is_eventd(&self) -> bool {
232        matches!(self, Event::EventD(_))
233    }
234
235    /// Returns `true` if the event is a `ServiceCheck`.
236    pub fn is_service_check(&self) -> bool {
237        matches!(self, Event::ServiceCheck(_))
238    }
239
240    /// Returns `true` if the event is a `Log`.
241    pub fn is_log(&self) -> bool {
242        matches!(self, Event::Log(_))
243    }
244
245    /// Returns `true` if the event is a `Trace`.
246    pub fn is_trace(&self) -> bool {
247        matches!(self, Event::Trace(_))
248    }
249}
250
251#[cfg(test)]
252mod tests {
253    use super::*;
254
255    #[test]
256    fn core_event_types_stay_within_size_budget() {
257        // `Event` and its variants are moved by value through the entire pipeline on every single data point, so
258        // accidental growth (an extra field, a large inline buffer, a widened enum discriminant) is a real performance
259        // regression rather than a cosmetic one.
260        //
261        // The budgets below are the current 64-bit layout sizes; if you intentionally change the layout of one of these
262        // types, update the corresponding budget in the same change.
263        macro_rules! assert_size_budget {
264            ($ty:ty, $budget:expr) => {{
265                let actual = std::mem::size_of::<$ty>();
266                assert!(
267                    actual <= $budget,
268                    "{} is {} bytes, exceeding its {}-byte budget",
269                    stringify!($ty),
270                    actual,
271                    $budget,
272                );
273            }};
274        }
275
276        assert_size_budget!(Event, 336);
277        assert_size_budget!(Metric, 160);
278        assert_size_budget!(saluki_context::Context, 8);
279        assert_size_budget!(super::metric::MetricValues, 104);
280        assert_size_budget!(super::metric::MetricMetadata, 48);
281        assert_size_budget!(EventD, 200);
282        assert_size_budget!(ServiceCheck, 160);
283        assert_size_budget!(Log, 192);
284        assert_size_budget!(Trace, 336);
285        assert_size_budget!(TraceStats, 24);
286    }
287
288    #[test]
289    fn event_type_display_renders_each_single_flag() {
290        // Note that a couple of the rendered names deliberately differ from the variant identifiers.
291        assert_eq!(EventType::Metric.to_string(), "Metric");
292        assert_eq!(EventType::EventD.to_string(), "DatadogEvent");
293        assert_eq!(EventType::ServiceCheck.to_string(), "ServiceCheck");
294        assert_eq!(EventType::Log.to_string(), "Log");
295        assert_eq!(EventType::Trace.to_string(), "Trace");
296        assert_eq!(EventType::TraceStats.to_string(), "TraceStats");
297    }
298
299    #[test]
300    fn event_type_display_joins_combined_flags_in_declaration_order() {
301        // Combined flags render in the fixed declaration order joined by `|`, regardless of how they were OR'd together.
302        assert_eq!((EventType::Log | EventType::Metric).to_string(), "Metric|Log");
303        assert_eq!(
304            EventType::all_bits().to_string(),
305            "Metric|DatadogEvent|ServiceCheck|Log|Trace|TraceStats"
306        );
307
308        // The empty bitmask (also the `Default`) renders as an empty string.
309        assert_eq!(EventType::none().to_string(), "");
310        assert_eq!(EventType::default().to_string(), "");
311    }
312}