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}