Skip to main content

obs_types/
sampling.rs

1//! [`SamplingReason`] — provenance recorded on the envelope.
2
3use std::str::FromStr;
4
5use buffa::Enumeration;
6use serde::{Deserialize, Serialize};
7
8use crate::UnknownVariant;
9
10/// Provenance recorded on the envelope explaining why an event was kept.
11///
12/// Head-sampler-dropped events never produce an envelope, so they need no
13/// enum value. See [10-data-model.md § 5](../../specs/10-data-model.md#5-sampling-provenance).
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
15#[serde(rename_all = "snake_case")]
16#[repr(i32)]
17#[non_exhaustive]
18pub enum SamplingReason {
19    /// Never appears in a well-formed envelope.
20    #[default]
21    Unspecified = 0,
22    /// Selected by head-rate roll.
23    HeadRate = 1,
24    /// Flushed because a sibling event hit `ERROR`/`FATAL`.
25    TailError = 2,
26    /// `always_log_slower_than_ms` triggered.
27    Slow = 3,
28    /// Emitted by `obs::forensic!` (always retained).
29    Forensic = 4,
30    /// AUDIT-tier event (always retained).
31    Audit = 5,
32    /// SDK self-event (`obs.runtime.v1.*`).
33    Runtime = 6,
34    /// Per-event `head_rate=1.0` forces always-on.
35    Override = 7,
36}
37
38impl SamplingReason {
39    /// Stable string label.
40    #[must_use]
41    pub const fn as_str(self) -> &'static str {
42        match self {
43            Self::Unspecified => "unspecified",
44            Self::HeadRate => "head_rate",
45            Self::TailError => "tail_error",
46            Self::Slow => "slow",
47            Self::Forensic => "forensic",
48            Self::Audit => "audit",
49            Self::Runtime => "runtime",
50            Self::Override => "override",
51        }
52    }
53}
54
55impl Enumeration for SamplingReason {
56    fn from_i32(value: i32) -> Option<Self> {
57        match value {
58            0 => Some(Self::Unspecified),
59            1 => Some(Self::HeadRate),
60            2 => Some(Self::TailError),
61            3 => Some(Self::Slow),
62            4 => Some(Self::Forensic),
63            5 => Some(Self::Audit),
64            6 => Some(Self::Runtime),
65            7 => Some(Self::Override),
66            _ => None,
67        }
68    }
69
70    fn to_i32(&self) -> i32 {
71        *self as i32
72    }
73
74    fn proto_name(&self) -> &'static str {
75        match self {
76            Self::Unspecified => "SAMPLING_REASON_UNSPECIFIED",
77            Self::HeadRate => "SAMPLING_REASON_HEAD_RATE",
78            Self::TailError => "SAMPLING_REASON_TAIL_ERROR",
79            Self::Slow => "SAMPLING_REASON_SLOW",
80            Self::Forensic => "SAMPLING_REASON_FORENSIC",
81            Self::Audit => "SAMPLING_REASON_AUDIT",
82            Self::Runtime => "SAMPLING_REASON_RUNTIME",
83            Self::Override => "SAMPLING_REASON_OVERRIDE",
84        }
85    }
86
87    fn from_proto_name(name: &str) -> Option<Self> {
88        match name {
89            "SAMPLING_REASON_UNSPECIFIED" => Some(Self::Unspecified),
90            "SAMPLING_REASON_HEAD_RATE" => Some(Self::HeadRate),
91            "SAMPLING_REASON_TAIL_ERROR" => Some(Self::TailError),
92            "SAMPLING_REASON_SLOW" => Some(Self::Slow),
93            "SAMPLING_REASON_FORENSIC" => Some(Self::Forensic),
94            "SAMPLING_REASON_AUDIT" => Some(Self::Audit),
95            "SAMPLING_REASON_RUNTIME" => Some(Self::Runtime),
96            "SAMPLING_REASON_OVERRIDE" => Some(Self::Override),
97            _ => None,
98        }
99    }
100
101    fn values() -> &'static [Self] {
102        &[
103            Self::Unspecified,
104            Self::HeadRate,
105            Self::TailError,
106            Self::Slow,
107            Self::Forensic,
108            Self::Audit,
109            Self::Runtime,
110            Self::Override,
111        ]
112    }
113}
114
115impl FromStr for SamplingReason {
116    type Err = UnknownVariant;
117
118    fn from_str(s: &str) -> Result<Self, Self::Err> {
119        match s.to_ascii_lowercase().as_str() {
120            "head_rate" => Ok(Self::HeadRate),
121            "tail_error" => Ok(Self::TailError),
122            "slow" => Ok(Self::Slow),
123            "forensic" => Ok(Self::Forensic),
124            "audit" => Ok(Self::Audit),
125            "runtime" => Ok(Self::Runtime),
126            "override" => Ok(Self::Override),
127            _ => Err(UnknownVariant {
128                kind: "SamplingReason",
129                value: s.to_string(),
130            }),
131        }
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    #[test]
140    fn test_should_round_trip_via_i32() {
141        for v in SamplingReason::values() {
142            assert_eq!(SamplingReason::from_i32(v.to_i32()), Some(*v));
143        }
144    }
145}