relay_base_schema/
data_category.rs

1//! Defines the [`DataCategory`] type that classifies data Relay can handle.
2
3use std::fmt;
4use std::str::FromStr;
5
6use serde::{Deserialize, Serialize};
7
8use crate::events::EventType;
9
10/// Classifies the type of data that is being ingested.
11#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
12#[serde(rename_all = "snake_case")]
13#[repr(i8)]
14pub enum DataCategory {
15    /// Reserved and unused.
16    Default = 0,
17    /// Error events and Events with an `event_type` not explicitly listed below.
18    Error = 1,
19    /// Transaction events.
20    Transaction = 2,
21    /// Events with an event type of `csp`, `hpkp`, `expectct` and `expectstaple`.
22    Security = 3,
23    /// An attachment. Quantity is the size of the attachment in bytes.
24    Attachment = 4,
25    /// Session updates. Quantity is the number of updates in the batch.
26    Session = 5,
27    /// Profile
28    ///
29    /// This is the category for processed profiles (all profiles, whether or not we store them).
30    Profile = 6,
31    /// Session Replays
32    Replay = 7,
33    /// DEPRECATED: A transaction for which metrics were extracted.
34    ///
35    /// This category is now obsolete because the `Transaction` variant will represent
36    /// processed transactions from now on.
37    TransactionProcessed = 8,
38    /// Indexed transaction events.
39    ///
40    /// This is the category for transaction payloads that were accepted and stored in full. In
41    /// contrast, `transaction` only guarantees that metrics have been accepted for the transaction.
42    TransactionIndexed = 9,
43    /// Monitor check-ins.
44    Monitor = 10,
45    /// Indexed Profile
46    ///
47    /// This is the category for indexed profiles that will be stored later.
48    ProfileIndexed = 11,
49    /// Span
50    ///
51    /// This is the category for spans from which we extracted metrics from.
52    Span = 12,
53    /// Monitor Seat
54    ///
55    /// Represents a monitor job that has scheduled monitor checkins. The seats are not ingested
56    /// but we define it here to prevent clashing values since this data category enumeration
57    /// is also used outside of Relay via the Python package.
58    MonitorSeat = 13,
59    /// User Feedback
60    ///
61    /// Represents a User Feedback processed.
62    /// Currently standardized on name UserReportV2 to avoid clashing with the old UserReport.
63    /// TODO(jferg): Rename this to UserFeedback once old UserReport is deprecated.
64    UserReportV2 = 14,
65    /// Metric buckets.
66    MetricBucket = 15,
67    /// SpanIndexed
68    ///
69    /// This is the category for spans we store in full.
70    SpanIndexed = 16,
71    /// ProfileDuration
72    ///
73    /// This data category is used to count the number of milliseconds per indexed profile chunk,
74    /// excluding UI profile chunks.
75    ProfileDuration = 17,
76    /// ProfileChunk
77    ///
78    /// This is a count of profile chunks received. It will not be used for billing but will be
79    /// useful for customers to track what's being dropped.
80    ProfileChunk = 18,
81    /// MetricSecond
82    ///
83    /// Reserved by billing to summarize the bucketed product of metric volume
84    /// and metric cardinality. Defined here so as not to clash with future
85    /// categories.
86    MetricSecond = 19,
87    /// Replay Video
88    ///
89    /// This is the data category for Session Replays produced via a video recording.
90    DoNotUseReplayVideo = 20,
91    /// This is the data category for Uptime monitors.
92    Uptime = 21,
93    /// Counts the number of individual attachments, as opposed to the number of bytes in an attachment.
94    AttachmentItem = 22,
95    /// LogItem
96    ///
97    /// This is the category for logs for which we store the count log events for users for measuring
98    /// missing breadcrumbs, and count of logs for rate limiting purposes.
99    LogItem = 23,
100    /// LogByte
101    ///
102    /// This is the category for logs for which we store log event total bytes for users.
103    LogByte = 24,
104    /// Profile duration of a UI profile.
105    ///
106    /// This data category is used to count the number of milliseconds per indexed UI profile
107    /// chunk.
108    ///
109    /// See also: [`Self::ProfileDuration`]
110    ProfileDurationUi = 25,
111    /// UI Profile Chunk.
112    ///
113    /// This data category is used to count the number of milliseconds per indexed UI profile
114    /// chunk.
115    ///
116    /// See also: [`Self::ProfileChunk`]
117    ProfileChunkUi = 26,
118
119    //
120    // IMPORTANT: After adding a new entry to DataCategory, go to the `relay-cabi` subfolder and run
121    // `make header` to regenerate the C-binding. This allows using the data category from Python.
122    // Rerun this step every time the **code name** of the variant is updated.
123    //
124    /// Any other data category not known by this Relay.
125    #[serde(other)]
126    Unknown = -1,
127}
128
129impl DataCategory {
130    /// Returns the data category corresponding to the given name.
131    pub fn from_name(string: &str) -> Self {
132        // TODO: This should probably use serde.
133        match string {
134            "default" => Self::Default,
135            "error" => Self::Error,
136            "transaction" => Self::Transaction,
137            "security" => Self::Security,
138            "attachment" => Self::Attachment,
139            "session" => Self::Session,
140            "profile" => Self::Profile,
141            "profile_indexed" => Self::ProfileIndexed,
142            "replay" => Self::Replay,
143            "transaction_processed" => Self::TransactionProcessed,
144            "transaction_indexed" => Self::TransactionIndexed,
145            "monitor" => Self::Monitor,
146            "span" => Self::Span,
147            "log_item" => Self::LogItem,
148            "log_byte" => Self::LogByte,
149            "monitor_seat" => Self::MonitorSeat,
150            "feedback" => Self::UserReportV2,
151            "user_report_v2" => Self::UserReportV2,
152            "metric_bucket" => Self::MetricBucket,
153            "span_indexed" => Self::SpanIndexed,
154            "profile_duration" => Self::ProfileDuration,
155            "profile_duration_ui" => Self::ProfileDurationUi,
156            "profile_chunk" => Self::ProfileChunk,
157            "profile_chunk_ui" => Self::ProfileChunkUi,
158            "metric_second" => Self::MetricSecond,
159            "replay_video" => Self::DoNotUseReplayVideo,
160            "uptime" => Self::Uptime,
161            "attachment_item" => Self::AttachmentItem,
162            _ => Self::Unknown,
163        }
164    }
165
166    /// Returns the canonical name of this data category.
167    pub fn name(self) -> &'static str {
168        // TODO: This should probably use serde.
169        match self {
170            Self::Default => "default",
171            Self::Error => "error",
172            Self::Transaction => "transaction",
173            Self::Security => "security",
174            Self::Attachment => "attachment",
175            Self::Session => "session",
176            Self::Profile => "profile",
177            Self::ProfileIndexed => "profile_indexed",
178            Self::Replay => "replay",
179            Self::DoNotUseReplayVideo => "replay_video",
180            Self::TransactionProcessed => "transaction_processed",
181            Self::TransactionIndexed => "transaction_indexed",
182            Self::Monitor => "monitor",
183            Self::Span => "span",
184            Self::LogItem => "log_item",
185            Self::LogByte => "log_byte",
186            Self::MonitorSeat => "monitor_seat",
187            Self::UserReportV2 => "feedback",
188            Self::MetricBucket => "metric_bucket",
189            Self::SpanIndexed => "span_indexed",
190            Self::ProfileDuration => "profile_duration",
191            Self::ProfileDurationUi => "profile_duration_ui",
192            Self::ProfileChunk => "profile_chunk",
193            Self::ProfileChunkUi => "profile_chunk_ui",
194            Self::MetricSecond => "metric_second",
195            Self::Uptime => "uptime",
196            Self::AttachmentItem => "attachment_item",
197            Self::Unknown => "unknown",
198        }
199    }
200
201    /// Returns true if the DataCategory refers to an error (i.e an error event).
202    pub fn is_error(self) -> bool {
203        matches!(self, Self::Error | Self::Default | Self::Security)
204    }
205
206    /// Returns the numeric value for this outcome.
207    pub fn value(self) -> Option<u8> {
208        // negative values (Internal and Unknown) cannot be sent as
209        // outcomes (internally so!)
210        (self as i8).try_into().ok()
211    }
212
213    /// Returns a dedicated category for indexing if this data can be converted to metrics.
214    ///
215    /// This returns `None` for most data categories.
216    pub fn index_category(self) -> Option<Self> {
217        match self {
218            Self::Transaction => Some(Self::TransactionIndexed),
219            Self::Span => Some(Self::SpanIndexed),
220            Self::Profile => Some(Self::ProfileIndexed),
221            _ => None,
222        }
223    }
224
225    /// Returns `true` if this data category is an indexed data category.
226    pub fn is_indexed(self) -> bool {
227        matches!(
228            self,
229            Self::TransactionIndexed | Self::SpanIndexed | Self::ProfileIndexed
230        )
231    }
232}
233
234impl fmt::Display for DataCategory {
235    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236        write!(f, "{}", self.name())
237    }
238}
239
240impl FromStr for DataCategory {
241    type Err = ();
242
243    fn from_str(string: &str) -> Result<Self, Self::Err> {
244        Ok(Self::from_name(string))
245    }
246}
247
248impl From<EventType> for DataCategory {
249    fn from(ty: EventType) -> Self {
250        match ty {
251            EventType::Default | EventType::Error | EventType::Nel => Self::Error,
252            EventType::Transaction => Self::Transaction,
253            EventType::Csp | EventType::Hpkp | EventType::ExpectCt | EventType::ExpectStaple => {
254                Self::Security
255            }
256            EventType::UserReportV2 => Self::UserReportV2,
257        }
258    }
259}