sentry_types/protocol/
session.rs

1use std::borrow::Cow;
2use std::fmt;
3use std::net::IpAddr;
4use std::str;
5use std::time::SystemTime;
6
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9use uuid::Uuid;
10
11use crate::utils::{ts_rfc3339, ts_rfc3339_opt};
12
13/// The Status of a Release Health Session.
14#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
15#[serde(rename_all = "snake_case")]
16pub enum SessionStatus {
17    /// The session is healthy.
18    ///
19    /// This does not necessarily indicate that the session is still active.
20    Ok,
21    /// The session terminated normally.
22    Exited,
23    /// The session resulted in an application crash.
24    Crashed,
25    /// The session had an unexpected abrupt termination (not crashing).
26    Abnormal,
27}
28
29impl Default for SessionStatus {
30    fn default() -> Self {
31        Self::Ok
32    }
33}
34
35/// An error used when parsing `SessionStatus`.
36#[derive(Debug, Error)]
37#[error("invalid session status")]
38pub struct ParseSessionStatusError;
39
40impl str::FromStr for SessionStatus {
41    type Err = ParseSessionStatusError;
42
43    fn from_str(string: &str) -> Result<Self, Self::Err> {
44        Ok(match string {
45            "ok" => SessionStatus::Ok,
46            "crashed" => SessionStatus::Crashed,
47            "abnormal" => SessionStatus::Abnormal,
48            "exited" => SessionStatus::Exited,
49            _ => return Err(ParseSessionStatusError),
50        })
51    }
52}
53
54impl fmt::Display for SessionStatus {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        match *self {
57            SessionStatus::Ok => write!(f, "ok"),
58            SessionStatus::Crashed => write!(f, "crashed"),
59            SessionStatus::Abnormal => write!(f, "abnormal"),
60            SessionStatus::Exited => write!(f, "exited"),
61        }
62    }
63}
64
65/// Additional attributes for Sessions.
66#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
67pub struct SessionAttributes<'a> {
68    /// The release version string.
69    pub release: Cow<'a, str>,
70
71    /// The environment identifier.
72    #[serde(default, skip_serializing_if = "Option::is_none")]
73    pub environment: Option<Cow<'a, str>>,
74
75    /// The ip address of the user. This data is not persisted but used for filtering.
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    pub ip_address: Option<IpAddr>,
78
79    /// The user agent of the user. This data is not persisted but used for filtering.
80    #[serde(default, skip_serializing_if = "Option::is_none")]
81    pub user_agent: Option<String>,
82}
83
84fn is_false(val: &bool) -> bool {
85    !val
86}
87
88/// A Release Health Session.
89///
90/// Refer to the [Sessions](https://develop.sentry.dev/sdk/sessions/) documentation
91/// for more details.
92#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
93pub struct SessionUpdate<'a> {
94    /// The session identifier.
95    #[serde(rename = "sid", default = "crate::random_uuid")]
96    pub session_id: Uuid,
97
98    /// The distinct identifier. Should be device or user ID.
99    #[serde(rename = "did", default)]
100    pub distinct_id: Option<String>,
101
102    /// An optional logical clock.
103    #[serde(rename = "seq", default, skip_serializing_if = "Option::is_none")]
104    pub sequence: Option<u64>,
105
106    /// The timestamp of when the session change event was created.
107    #[serde(
108        default,
109        skip_serializing_if = "Option::is_none",
110        with = "ts_rfc3339_opt"
111    )]
112    pub timestamp: Option<SystemTime>,
113
114    /// The timestamp of when the session itself started.
115    #[serde(default = "SystemTime::now", with = "ts_rfc3339")]
116    pub started: SystemTime,
117
118    /// A flag that indicates that this is the initial transmission of the session.
119    #[serde(default, skip_serializing_if = "is_false")]
120    pub init: bool,
121
122    /// An optional duration of the session so far.
123    #[serde(default, skip_serializing_if = "Option::is_none")]
124    pub duration: Option<f64>,
125
126    /// The status of the session.
127    #[serde(default)]
128    pub status: SessionStatus,
129
130    /// The number of errors that occurred.
131    #[serde(default)]
132    pub errors: u64,
133
134    /// The session event attributes.
135    #[serde(rename = "attrs")]
136    pub attributes: SessionAttributes<'a>,
137}
138
139#[allow(clippy::trivially_copy_pass_by_ref)]
140fn is_zero(val: &u32) -> bool {
141    *val == 0
142}
143
144/// An aggregation grouped by `started` and `distinct_id`.
145#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
146pub struct SessionAggregateItem {
147    /// The timestamp of when the session itself started.
148    #[serde(with = "ts_rfc3339")]
149    pub started: SystemTime,
150    /// The distinct identifier.
151    #[serde(rename = "did", default, skip_serializing_if = "Option::is_none")]
152    pub distinct_id: Option<String>,
153    /// The number of exited sessions that occurred.
154    #[serde(default, skip_serializing_if = "is_zero")]
155    pub exited: u32,
156    /// The number of errored sessions that occurred, not including the abnormal and crashed ones.
157    #[serde(default, skip_serializing_if = "is_zero")]
158    pub errored: u32,
159    /// The number of abnormal sessions that occurred.
160    #[serde(default, skip_serializing_if = "is_zero")]
161    pub abnormal: u32,
162    /// The number of crashed sessions that occurred.
163    #[serde(default, skip_serializing_if = "is_zero")]
164    pub crashed: u32,
165}
166
167/// An Aggregation of Release Health Sessions
168///
169/// For *request-mode* sessions, sessions will be aggregated instead of being
170/// sent as individual updates.
171#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
172pub struct SessionAggregates<'a> {
173    /// A batch of sessions that were started.
174    #[serde(default)]
175    pub aggregates: Vec<SessionAggregateItem>,
176    /// The shared session event attributes.
177    #[serde(rename = "attrs")]
178    pub attributes: SessionAttributes<'a>,
179}