modo/tracing/sentry.rs
1use crate::error::Result;
2use crate::runtime::Task;
3
4use serde::Deserialize;
5
6/// Sentry error and performance reporting settings.
7///
8/// Embed in `Config::sentry` and supply a valid DSN to enable Sentry.
9///
10/// ```yaml
11/// tracing:
12/// sentry:
13/// dsn: "https://key@sentry.io/project"
14/// environment: production
15/// sample_rate: 1.0
16/// traces_sample_rate: 0.1
17/// ```
18#[non_exhaustive]
19#[derive(Debug, Clone, Deserialize)]
20#[serde(default)]
21pub struct SentryConfig {
22 /// Sentry DSN. When empty, Sentry is not initialised.
23 pub dsn: String,
24
25 /// Environment tag reported to Sentry (e.g. `"production"`).
26 ///
27 /// Defaults to the value of `APP_ENV` (see [`crate::config::env`]).
28 pub environment: String,
29
30 /// Fraction of error events to send (0.0–1.0). Defaults to `1.0`.
31 pub sample_rate: f32,
32
33 /// Fraction of transactions to trace for performance monitoring (0.0–1.0).
34 /// Defaults to `0.1`.
35 pub traces_sample_rate: f32,
36}
37
38impl Default for SentryConfig {
39 fn default() -> Self {
40 Self {
41 dsn: String::new(),
42 environment: crate::config::env(),
43 sample_rate: 1.0,
44 traces_sample_rate: 0.1,
45 }
46 }
47}
48
49/// RAII guard that keeps the tracing subscriber and Sentry client alive.
50///
51/// Returned by [`crate::tracing::init`]. Hold this value for the entire
52/// lifetime of the process — typically by passing it to the `run!` macro
53/// or calling [`Task::shutdown`] at the end of `main`.
54///
55/// Dropping the guard without calling `shutdown` is safe but may not flush
56/// all buffered Sentry events.
57pub struct TracingGuard {
58 _sentry: Option<sentry::ClientInitGuard>,
59}
60
61impl Default for TracingGuard {
62 fn default() -> Self {
63 Self::new()
64 }
65}
66
67impl TracingGuard {
68 /// Create a guard with no active Sentry client.
69 pub fn new() -> Self {
70 Self { _sentry: None }
71 }
72
73 /// Create a guard that owns an active Sentry client.
74 pub fn with_sentry(guard: sentry::ClientInitGuard) -> Self {
75 Self {
76 _sentry: Some(guard),
77 }
78 }
79}
80
81impl Task for TracingGuard {
82 /// Flush pending Sentry events (up to 5 seconds) and release the client.
83 async fn shutdown(self) -> Result<()> {
84 if let Some(guard) = self._sentry {
85 guard.close(Some(std::time::Duration::from_secs(5)));
86 }
87 Ok(())
88 }
89}