sentry/
init.rs

1use std::sync::Arc;
2
3use sentry_core::sentry_debug;
4#[cfg(feature = "release-health")]
5use sentry_core::SessionMode;
6
7use crate::defaults::apply_defaults;
8use crate::{Client, ClientOptions, Hub};
9
10/// Helper struct that is returned from `init`.
11///
12/// When this is dropped events are drained with the configured `shutdown_timeout`.
13#[must_use = "when the init guard is dropped the send queue is flushed and the \
14              transport will be shut down and no further events can be sent."]
15pub struct ClientInitGuard(Arc<Client>);
16
17impl std::ops::Deref for ClientInitGuard {
18    type Target = Client;
19    fn deref(&self) -> &Self::Target {
20        &self.0
21    }
22}
23
24impl ClientInitGuard {
25    /// Quick check if the client is enabled.
26    pub fn is_enabled(&self) -> bool {
27        self.0.is_enabled()
28    }
29}
30
31impl Drop for ClientInitGuard {
32    fn drop(&mut self) {
33        if self.is_enabled() {
34            sentry_debug!("dropping client guard -> disposing client");
35        } else {
36            sentry_debug!("dropping client guard (no client to dispose)");
37        }
38        // end any session that might be open before closing the client
39        #[cfg(feature = "release-health")]
40        crate::end_session();
41        self.0.close(None);
42    }
43}
44
45/// Creates the Sentry client for a given client config and binds it.
46///
47/// This returns a client init guard that must be kept in scope and that will help the
48/// client send events before the application closes. When the guard is
49/// dropped, then the transport that was initialized shuts down and no
50/// further events can be sent on it.
51///
52/// If you don't want (or can not) keep the guard around, it's permissible to
53/// call `mem::forget` on it.
54///
55/// # Examples
56///
57/// ```
58/// let _sentry = sentry::init("https://key@sentry.io/1234");
59/// ```
60///
61/// Or if draining on shutdown should be ignored:
62/// This is not recommended, as events or session updates that have been queued
63/// might be lost.
64///
65/// ```
66/// std::mem::forget(sentry::init("https://key@sentry.io/1234"));
67/// ```
68///
69/// The guard returned can also be inspected to see if a client has been
70/// created to enable further configuration:
71///
72/// ```
73/// let sentry = sentry::init(sentry::ClientOptions {
74///     release: Some("foo-bar-baz@1.0.0".into()),
75///     ..Default::default()
76/// });
77/// if sentry.is_enabled() {
78///     // some other initialization
79/// }
80/// ```
81///
82/// This behaves similar to creating a client by calling `Client::from_config`
83/// and to then bind it to the hub except it also applies default integrations,
84/// a default transport, as well as other options populated from environment
85/// variables.
86/// For more information about the formats accepted see `Client::from_config`,
87/// and `ClientOptions`.
88///
89/// # Panics
90///
91/// This will panic when the provided DSN is invalid.
92/// If you want to handle invalid DSNs you need to parse them manually by
93/// calling `parse` on each of them and handle the error.
94pub fn init<C>(opts: C) -> ClientInitGuard
95where
96    C: Into<ClientOptions>,
97{
98    let opts = apply_defaults(opts.into());
99
100    #[allow(unused)]
101    let auto_session_tracking = opts.auto_session_tracking;
102    #[allow(unused)]
103    let session_mode = opts.session_mode;
104
105    let client = Arc::new(Client::from(opts));
106
107    Hub::with(|hub| hub.bind_client(Some(client.clone())));
108    if let Some(dsn) = client.dsn() {
109        sentry_debug!("enabled sentry client for DSN {}", dsn);
110    } else {
111        sentry_debug!("initialized disabled sentry client due to disabled or invalid DSN");
112    }
113    #[cfg(feature = "release-health")]
114    if auto_session_tracking && session_mode == SessionMode::Application {
115        crate::start_session()
116    }
117    ClientInitGuard(client)
118}