relay_server/metrics_extraction/sessions/
types.rs1use std::collections::BTreeMap;
2use std::fmt::{self, Display};
3
4use relay_common::time::UnixTimestamp;
5use relay_event_schema::protocol::SessionStatus;
6use relay_metrics::{
7 Bucket, BucketMetadata, BucketValue, CounterType, MetricNamespace, MetricResourceIdentifier,
8 MetricUnit,
9};
10use uuid::Uuid;
11
12use crate::metrics_extraction::IntoMetric;
13
14#[derive(Clone, Debug, PartialEq)]
16pub enum SessionMetric {
17 Session {
19 counter: CounterType,
20 tags: SessionSessionTags,
21 },
22 User {
24 distinct_id: String,
25 tags: SessionUserTags,
26 },
27 Error { session_id: Uuid, tags: CommonTags },
32}
33
34#[derive(Clone, Debug, PartialEq, Eq)]
36pub struct SessionSessionTags {
37 pub status: String,
38 pub common_tags: CommonTags,
39}
40
41#[derive(Clone, Debug, PartialEq, Eq)]
43pub struct SessionUserTags {
44 pub status: Option<SessionStatus>,
45 pub abnormal_mechanism: Option<String>,
46 pub common_tags: CommonTags,
47}
48
49#[derive(Clone, Debug, PartialEq, Eq)]
51pub struct CommonTags {
52 pub release: String,
53 pub environment: Option<String>,
54 pub sdk: Option<String>,
55}
56
57impl From<CommonTags> for BTreeMap<String, String> {
58 fn from(value: CommonTags) -> Self {
59 let mut map = BTreeMap::new();
60
61 map.insert("release".to_owned(), value.release);
62
63 if let Some(environment) = value.environment {
64 map.insert("environment".into(), environment);
65 }
66
67 if let Some(sdk) = value.sdk {
68 map.insert("sdk".to_owned(), sdk);
69 }
70 map
71 }
72}
73
74impl From<SessionUserTags> for BTreeMap<String, String> {
75 fn from(value: SessionUserTags) -> Self {
76 let mut map: BTreeMap<String, String> = value.common_tags.into();
77 if let Some(status) = value.status {
78 map.insert("session.status".to_owned(), status.to_string());
79 }
80
81 if let Some(abnormal_mechanism) = value.abnormal_mechanism {
82 map.insert("abnormal_mechanism".to_owned(), abnormal_mechanism);
83 }
84
85 map
86 }
87}
88
89impl From<SessionSessionTags> for BTreeMap<String, String> {
90 fn from(value: SessionSessionTags) -> Self {
91 let mut map: BTreeMap<String, String> = value.common_tags.into();
92 map.insert("session.status".to_owned(), value.status);
93
94 map
95 }
96}
97
98impl IntoMetric for SessionMetric {
99 fn into_metric(self, timestamp: UnixTimestamp) -> Bucket {
100 let name = self.to_string();
101
102 let (value, tags) = match self {
103 SessionMetric::Error {
104 session_id: id,
105 tags,
106 } => (BucketValue::set_from_display(id), tags.into()),
107 SessionMetric::User { distinct_id, tags } => {
108 (BucketValue::set_from_display(distinct_id), tags.into())
109 }
110 SessionMetric::Session { counter, tags } => {
111 (BucketValue::Counter(counter), tags.into())
112 }
113 };
114
115 let mri = MetricResourceIdentifier {
116 ty: value.ty(),
117 namespace: MetricNamespace::Sessions,
118 name: name.into(),
119 unit: MetricUnit::None,
120 };
121
122 let received_at = if cfg!(not(test)) {
125 UnixTimestamp::now()
126 } else {
127 UnixTimestamp::from_secs(0)
128 };
129
130 Bucket {
131 timestamp,
132 width: 0,
133 name: mri.to_string().into(),
134 value,
135 tags,
136 metadata: BucketMetadata::new(received_at),
137 }
138 }
139}
140
141impl Display for SessionMetric {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 match self {
144 Self::Session { .. } => write!(f, "session"),
145 Self::User { .. } => write!(f, "user"),
146 Self::Error { .. } => write!(f, "error"),
147 }
148 }
149}