Skip to main content

sentry_core/
clientoptions.rs

1use std::borrow::Cow;
2use std::fmt;
3use std::sync::Arc;
4use std::time::Duration;
5
6use crate::constants::USER_AGENT;
7use crate::performance::{TracesSampler, TransactionContext};
8use crate::protocol::{Breadcrumb, Event, Log, Metric, OrganizationId};
9use crate::types::Dsn;
10use crate::{Integration, IntoDsn, TransportFactory};
11
12/// Type alias for before event/breadcrumb handlers.
13pub type BeforeCallback<T> = Arc<dyn Fn(T) -> Option<T> + Send + Sync>;
14
15/// The Session Mode of the SDK.
16///
17/// Depending on the use-case, the SDK can be set to two different session modes:
18///
19/// * **Application Mode Sessions**:
20///   This mode should be used for user-attended programs, which typically have
21///   a single long running session that span the applications' lifetime.
22///
23/// * **Request Mode Sessions**:
24///   This mode is intended for servers that use one session per incoming
25///   request, and thus have a lot of very short lived sessions.
26///
27/// Setting the SDK to *request-mode* sessions means that session durations will
28/// not be tracked, and sessions will be pre-aggregated before being sent upstream.
29/// This applies both to automatic and manually triggered sessions.
30///
31/// **NOTE**: Support for *request-mode* sessions was added in Sentry `21.2`.
32///
33/// See the
34/// [Documentation on Session Modes](https://develop.sentry.dev/sdk/sessions/#sdk-considerations)
35/// for more information.
36///
37/// **NOTE**: The `release-health` feature (enabled by default) needs to be enabled for this
38/// option to have any effect.
39#[derive(Copy, Clone, Debug, PartialEq, Eq)]
40pub enum SessionMode {
41    /// Long running application session.
42    Application,
43    /// Lots of short per-request sessions.
44    Request,
45}
46
47/// The maximum size of an HTTP request body that the SDK captures.
48///
49/// Only request bodies that parse as JSON or form data are currently captured.
50/// See the Sentry documentation on [attaching request bodies] and [handling sensitive data] for
51/// more information.
52///
53/// [attaching request bodies]: https://develop.sentry.dev/sdk/expected-features/#attaching-request-body-in-server-sdks
54/// [handling sensitive data]: https://develop.sentry.dev/sdk/expected-features/data-handling/#sensitive-data
55#[derive(Clone, Copy, PartialEq)]
56pub enum MaxRequestBodySize {
57    /// Don't capture request body
58    None,
59    /// Capture up to 1000 bytes
60    Small,
61    /// Capture up to 10000 bytes
62    Medium,
63    /// Capture entire body
64    Always,
65    /// Capture up to a specific size
66    Explicit(usize),
67}
68
69impl MaxRequestBodySize {
70    /// Check if the content length is within the size limit.
71    pub fn is_within_size_limit(&self, content_length: usize) -> bool {
72        match self {
73            MaxRequestBodySize::None => false,
74            MaxRequestBodySize::Small => content_length <= 1_000,
75            MaxRequestBodySize::Medium => content_length <= 10_000,
76            MaxRequestBodySize::Always => true,
77            MaxRequestBodySize::Explicit(size) => content_length <= *size,
78        }
79    }
80}
81
82/// Defines how traces should be sampled.
83///
84/// Leaving this at [`Disabled`](Self::Disabled) is distinct from explicitly configuring
85/// [`FixedRate`](Self::FixedRate) with a rate of `0.0`. Both disable local transaction sampling
86/// when there is no parent sampling decision, but an explicit fixed-rate strategy can still honor
87/// an inherited sampling decision.
88#[derive(Clone, Default)]
89#[non_exhaustive]
90pub enum TracesSamplingStrategy {
91    /// Sample the trace at a fixed sample rate. The rate should be between 0.0 and 1.0, inclusive.
92    FixedRate(f32),
93    /// Sample the traces using a [`TracesSampler`] function.
94    Function(Arc<TracesSampler>),
95    /// Disable tracing.
96    #[default]
97    Disabled,
98}
99
100impl fmt::Debug for TracesSamplingStrategy {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        match self {
103            Self::FixedRate(rate) => f.debug_tuple("FixedRate").field(rate).finish(),
104            Self::Function(callback) => f
105                .debug_tuple("Function")
106                .field(&format_args!("{:p}", Arc::as_ptr(callback)))
107                .finish(),
108            Self::Disabled => f.write_str("Disabled"),
109        }
110    }
111}
112
113/// The sampling strategy for events.
114///
115/// Currently, we only support fixed rates. This defaults to `Self::FixedRate(1.0)`.
116#[derive(Clone, Debug)]
117#[non_exhaustive]
118pub enum EventSamplingStrategy {
119    /// Sample events at a fixed sample rate. The rate should be between 0.0 and 1.0, inclusive.
120    FixedRate(f32),
121}
122
123impl Default for EventSamplingStrategy {
124    fn default() -> Self {
125        Self::FixedRate(1.0)
126    }
127}
128
129/// Configuration settings for the client.
130///
131/// These options are explained in more detail in the general
132/// [sentry documentation](https://docs.sentry.io/error-reporting/configuration/?platform=rust).
133///
134/// # Examples
135///
136/// ```
137/// let _options = sentry::ClientOptions::new().debug(true);
138/// ```
139#[derive(Clone)]
140#[must_use = "ClientOptions must be passed to sentry::init to have any effect"]
141#[non_exhaustive]
142pub struct ClientOptions {
143    // Common options
144    /// The DSN to use.
145    ///
146    /// See [`dsn`](method@ClientOptions::dsn) for details.
147    pub dsn: Option<Dsn>,
148    /// Enables debug mode.
149    ///
150    /// See [`debug`](method@ClientOptions::debug) for details.
151    pub debug: bool,
152    /// The release to be sent with events.
153    ///
154    /// See [`release`](method@ClientOptions::release) for details.
155    pub release: Option<Cow<'static, str>>,
156    /// The environment to be sent with events.
157    ///
158    /// See [`environment`](method@ClientOptions::environment) for details.
159    pub environment: Option<Cow<'static, str>>,
160    /// The sampling strategy for event submission.
161    ///
162    /// This can be set to with [`sample_rate`](method@ClientOptions::sample_rate).
163    pub event_sampling_strategy: EventSamplingStrategy,
164    /// The traces sampling strategy.
165    ///
166    /// This can be set to a fixed rate with
167    /// [`traces_sample_rate`](method@ClientOptions::traces_sample_rate), a function with
168    /// [`traces_sampler`](method@ClientOptions::traces_sampler), or can be left at the default
169    /// disabled value.
170    pub traces_sampling_strategy: TracesSamplingStrategy,
171    /// The organization ID used for trace continuation.
172    ///
173    /// See [`org_id`](method@ClientOptions::org_id) for details.
174    pub org_id: Option<OrganizationId>,
175    /// Enables strict trace continuation.
176    ///
177    /// See [`strict_trace_continuation`](method@ClientOptions::strict_trace_continuation) for
178    /// details.
179    pub strict_trace_continuation: bool,
180    /// Maximum number of breadcrumbs.
181    ///
182    /// See [`max_breadcrumbs`](method@ClientOptions::max_breadcrumbs) for details.
183    pub max_breadcrumbs: usize,
184    /// Attaches stacktraces to messages.
185    ///
186    /// See [`attach_stacktrace`](method@ClientOptions::attach_stacktrace) for details.
187    pub attach_stacktrace: bool,
188    /// Whether to send default PII.
189    ///
190    /// See [`send_default_pii`](method@ClientOptions::send_default_pii) for details.
191    pub send_default_pii: bool,
192    /// The server name to be reported.
193    ///
194    /// See [`server_name`](method@ClientOptions::server_name) for details.
195    pub server_name: Option<Cow<'static, str>>,
196    /// Module prefixes that are always considered "in_app".
197    ///
198    /// See [`in_app_include`](method@ClientOptions::in_app_include) for details.
199    pub in_app_include: Vec<&'static str>,
200    /// Module prefixes that are never "in_app".
201    ///
202    /// See [`in_app_exclude`](method@ClientOptions::in_app_exclude) for details.
203    pub in_app_exclude: Vec<&'static str>,
204    // Integration options
205    /// A list of integrations to enable.
206    ///
207    /// See [`integrations`](method@ClientOptions::integrations) and
208    /// [`add_integration`](method@ClientOptions::add_integration) for details.
209    pub integrations: Vec<Arc<dyn Integration>>,
210    /// Whether to add default integrations.
211    ///
212    /// See [`default_integrations`](method@ClientOptions::default_integrations) for details.
213    pub default_integrations: bool,
214    // Hooks
215    /// Callback that is executed before event sending.
216    ///
217    /// See [`before_send`](method@ClientOptions::before_send) for details.
218    pub before_send: Option<BeforeCallback<Event<'static>>>,
219    /// Callback that is executed for each Breadcrumb being added.
220    ///
221    /// See [`before_breadcrumb`](method@ClientOptions::before_breadcrumb) for details.
222    pub before_breadcrumb: Option<BeforeCallback<Breadcrumb>>,
223    /// Callback that is executed for each Log being added.
224    ///
225    /// See [`before_send_log`](method@ClientOptions::before_send_log) for details.
226    pub before_send_log: Option<BeforeCallback<Log>>,
227    // Transport options
228    /// The transport to use.
229    ///
230    /// See [`transport`](method@ClientOptions::transport) for details.
231    pub transport: Option<Arc<dyn TransportFactory>>,
232    /// An optional HTTP proxy to use.
233    ///
234    /// See [`http_proxy`](method@ClientOptions::http_proxy) for details.
235    pub http_proxy: Option<Cow<'static, str>>,
236    /// An optional HTTPS proxy to use.
237    ///
238    /// See [`https_proxy`](method@ClientOptions::https_proxy) for details.
239    pub https_proxy: Option<Cow<'static, str>>,
240    /// The timeout on client drop for draining events on shutdown.
241    ///
242    /// See [`shutdown_timeout`](method@ClientOptions::shutdown_timeout) for details.
243    pub shutdown_timeout: Duration,
244    /// The maximum size of an HTTP request body to capture.
245    ///
246    /// See [`max_request_body_size`](method@ClientOptions::max_request_body_size) for details.
247    pub max_request_body_size: MaxRequestBodySize,
248    /// Deprecated. Setting this to `false` only disables automatic log capture by the
249    /// log-capturing integrations (`log` and `tracing` with the `logs` feature); it does not
250    /// disable logs captured manually via [`Hub::capture_log`](crate::Hub::capture_log) and the
251    /// `logger_*` macros. Defaults to `true`.
252    ///
253    /// To stop an integration from sending logs, use its own options to configure what it
254    /// captures.
255    #[deprecated = "logs captured manually are always sent; only automatic capture by integrations respects this option"]
256    pub enable_logs: bool,
257    /// Deprecated no-op. Metrics are always enabled, regardless of this option's value.
258    #[deprecated = "this option is a deprecated no-op"]
259    pub enable_metrics: bool,
260    /// Callback that is executed for each [`Metric`] before sending.
261    ///
262    /// See [`before_send_metric`](method@ClientOptions::before_send_metric) for details.
263    pub before_send_metric: Option<BeforeCallback<Metric>>,
264    // Other options not documented in Unified API
265    /// Whether to disable SSL verification.
266    ///
267    /// See [`accept_invalid_certs`](method@ClientOptions::accept_invalid_certs) for details.
268    pub accept_invalid_certs: bool,
269    /// Whether Release Health Session tracking is enabled.
270    ///
271    /// See [`auto_session_tracking`](method@ClientOptions::auto_session_tracking) for details.
272    pub auto_session_tracking: bool,
273    /// Determine how Sessions are being tracked.
274    ///
275    /// See [`session_mode`](method@ClientOptions::session_mode) for details.
276    pub session_mode: SessionMode,
277    /// The user agent that should be reported.
278    ///
279    /// See [`user_agent`](method@ClientOptions::user_agent) for details.
280    pub user_agent: Cow<'static, str>,
281}
282
283impl ClientOptions {
284    /// Creates new Options.
285    #[inline]
286    pub fn new() -> Self {
287        Self::default()
288    }
289
290    /// Sets the [DSN](field@ClientOptions::dsn) to use.
291    ///
292    /// # Panics
293    ///
294    /// Panics if the value fails to parse as a [DSN](`Dsn`).
295    #[inline]
296    pub fn dsn(self, dsn: &str) -> Self {
297        let dsn = Some(dsn.parse().expect("invalid value for DSN"));
298        Self { dsn, ..self }
299    }
300
301    /// Enables or disables [debug mode](field@ClientOptions::debug).
302    ///
303    /// In debug mode debug information is printed to stderr to help you understand what sentry is
304    /// doing. Defaults to `false`.
305    #[inline]
306    pub fn debug(self, debug: bool) -> Self {
307        Self { debug, ..self }
308    }
309
310    /// Sets the [release](field@ClientOptions::release) to be sent with events.
311    #[inline]
312    pub fn release<T>(self, release: T) -> Self
313    where
314        T: Into<Cow<'static, str>>,
315    {
316        let release = Some(release.into());
317        Self { release, ..self }
318    }
319
320    /// Sets the [release](field@ClientOptions::release) to be sent with events if one is provided.
321    ///
322    /// Use this with [`release_name!`](crate::release_name), which returns the release as an
323    /// `Option`.
324    #[inline]
325    pub fn maybe_release<T>(self, release: Option<T>) -> Self
326    where
327        T: Into<Cow<'static, str>>,
328    {
329        match release {
330            Some(release) => self.release(release),
331            None => self,
332        }
333    }
334
335    /// Sets the [environment](field@ClientOptions::environment) to be sent with events.
336    ///
337    /// Defaults to either `"development"` or `"production"` depending on the `debug_assertions`
338    /// cfg-attribute.
339    #[inline]
340    pub fn environment<T>(self, environment: T) -> Self
341    where
342        T: Into<Cow<'static, str>>,
343    {
344        let environment = Some(environment.into());
345        Self {
346            environment,
347            ..self
348        }
349    }
350
351    /// Sets the [event sampling strategy](field@ClientOptions::event_sampling_strategy) to a fixed
352    /// sample rate for event submission.
353    ///
354    /// Must be between `0.0` and `1.0`. Defaults to `1.0`.
355    ///
356    /// # Panics
357    ///
358    /// Panics if the `sample_rate` is outside the allowed range.
359    #[inline]
360    pub fn sample_rate(self, sample_rate: f32) -> Self {
361        if !(0.0..=1.0).contains(&sample_rate) {
362            panic!("Sample rate {sample_rate} is outside the allowed range [0.0, 1.0].")
363        }
364
365        let event_sampling_strategy = EventSamplingStrategy::FixedRate(sample_rate);
366
367        Self {
368            event_sampling_strategy,
369            ..self
370        }
371    }
372
373    /// Sets the [traces sampling strategy](field@ClientOptions::traces_sampling_strategy) to a
374    /// fixed sample rate for tracing transactions.
375    ///
376    /// Must be between `0.0` and `1.0`.
377    ///
378    /// Calling this method stores an explicit fixed-rate traces sampling strategy, even when the
379    /// rate is `0.0`. That is distinct from leaving traces sampling unset, which uses
380    /// [`TracesSamplingStrategy::Disabled`].
381    ///
382    /// # Panics
383    ///
384    /// Panics if the `traces_sample_rate` is outside the allowed range.
385    #[inline]
386    pub fn traces_sample_rate(self, traces_sample_rate: f32) -> Self {
387        if !(0.0..=1.0).contains(&traces_sample_rate) {
388            panic!(
389                "Traces sample rate {traces_sample_rate} is outside the allowed range [0.0, 1.0]."
390            )
391        }
392
393        let traces_sampling_strategy = TracesSamplingStrategy::FixedRate(traces_sample_rate);
394
395        Self {
396            traces_sampling_strategy,
397            ..self
398        }
399    }
400
401    /// Sets the [traces sampling strategy](field@ClientOptions::traces_sampling_strategy) to a
402    /// sampler callback for tracing transactions.
403    ///
404    /// Return a sample rate between `0.0` and `1.0` for the transaction in question. This replaces
405    /// any fixed-rate strategy configured with [`Self::traces_sample_rate`] and is distinct from
406    /// leaving traces sampling unset.
407    #[inline]
408    pub fn traces_sampler<F>(self, traces_sampler: F) -> Self
409    where
410        F: Fn(&TransactionContext) -> f32 + Send + Sync + 'static,
411    {
412        let traces_sampling_strategy =
413            TracesSamplingStrategy::Function(Arc::new(traces_sampler) as Arc<TracesSampler>);
414
415        Self {
416            traces_sampling_strategy,
417            ..self
418        }
419    }
420
421    /// Sets the [organization ID](field@ClientOptions::org_id) used for trace continuation.
422    ///
423    /// By default, we infer the organization ID from the DSN when available. Setting this option
424    /// overrides the DSN-derived organization ID.
425    ///
426    /// This option should be used in local Relay and self-hosted setups, as the organization ID
427    /// cannot be inferred from the DSN in these cases.
428    #[inline]
429    pub fn org_id(self, org_id: OrganizationId) -> Self {
430        let org_id = Some(org_id);
431        Self { org_id, ..self }
432    }
433
434    /// Enables or disables [strict trace continuation](field@ClientOptions::strict_trace_continuation).
435    ///
436    /// Strict trace continuation helps prevent the SDK from continuing traces that originate from
437    /// services instrumented with Sentry by another organization.
438    ///
439    /// By default, the SDK will always continue incoming traces, unless this SDK has an org ID
440    /// embedded in the DSN or explicitly set with [`Self::org_id`] **and** the incoming trace
441    /// includes a different org ID.
442    ///
443    /// When strict trace continuation is enabled, the SDK additionally will not continue traces in
444    /// the case where one of the SDK's org ID or the incoming trace org ID are missing.
445    #[inline]
446    pub fn strict_trace_continuation(self, strict_trace_continuation: bool) -> Self {
447        Self {
448            strict_trace_continuation,
449            ..self
450        }
451    }
452
453    /// Sets the [maximum number of breadcrumbs](field@ClientOptions::max_breadcrumbs).
454    ///
455    /// Defaults to `100`.
456    #[inline]
457    pub fn max_breadcrumbs(self, max_breadcrumbs: usize) -> Self {
458        Self {
459            max_breadcrumbs,
460            ..self
461        }
462    }
463
464    /// Enables or disables [attaching stacktraces](field@ClientOptions::attach_stacktrace) to
465    /// messages.
466    ///
467    /// Defaults to `false`.
468    #[inline]
469    pub fn attach_stacktrace(self, attach_stacktrace: bool) -> Self {
470        Self {
471            attach_stacktrace,
472            ..self
473        }
474    }
475
476    /// Enables or disables sending [default PII](field@ClientOptions::send_default_pii).
477    ///
478    /// This includes information such as potentially sensitive HTTP headers and user IP addresses
479    /// in HTTP server integrations. Defaults to `false`.
480    #[inline]
481    pub fn send_default_pii(self, send_default_pii: bool) -> Self {
482        Self {
483            send_default_pii,
484            ..self
485        }
486    }
487
488    /// Sets the [server name](field@ClientOptions::server_name) to be reported.
489    #[inline]
490    pub fn server_name<T>(self, server_name: T) -> Self
491    where
492        T: Into<Cow<'static, str>>,
493    {
494        let server_name = Some(server_name.into());
495        Self {
496            server_name,
497            ..self
498        }
499    }
500
501    /// Sets [module prefixes](field@ClientOptions::in_app_include) that are always considered
502    /// in-app.
503    #[inline]
504    pub fn in_app_include<I>(self, in_app_include: I) -> Self
505    where
506        I: IntoIterator<Item = &'static str>,
507    {
508        let in_app_include = in_app_include.into_iter().collect();
509        Self {
510            in_app_include,
511            ..self
512        }
513    }
514
515    /// Sets [module prefixes](field@ClientOptions::in_app_exclude) that are never considered
516    /// in-app.
517    #[inline]
518    pub fn in_app_exclude<I>(self, in_app_exclude: I) -> Self
519    where
520        I: IntoIterator<Item = &'static str>,
521    {
522        let in_app_exclude = in_app_exclude.into_iter().collect();
523        Self {
524            in_app_exclude,
525            ..self
526        }
527    }
528
529    /// Sets the [integrations](field@ClientOptions::integrations) to enable, replacing the
530    /// existing list.
531    ///
532    /// See [`sentry::integrations`](integrations/index.html#installing-integrations) for how to
533    /// use this to enable extra integrations. Use
534    /// [`add_integration`](method@ClientOptions::add_integration) to append.
535    #[inline]
536    pub fn integrations<I>(self, integrations: I) -> Self
537    where
538        I: IntoIterator<Item = Arc<dyn Integration>>,
539    {
540        let integrations = integrations.into_iter().collect();
541        Self {
542            integrations,
543            ..self
544        }
545    }
546
547    /// Enables or disables [default integrations](field@ClientOptions::default_integrations).
548    ///
549    /// See [`sentry::integrations`](integrations/index.html#default-integrations) for details.
550    /// Defaults to `true`.
551    #[inline]
552    pub fn default_integrations(self, default_integrations: bool) -> Self {
553        Self {
554            default_integrations,
555            ..self
556        }
557    }
558
559    /// Sets the [callback](field@ClientOptions::before_send) that is executed before event
560    /// sending.
561    #[inline]
562    pub fn before_send<F>(self, before_send: F) -> Self
563    where
564        F: Fn(Event<'static>) -> Option<Event<'static>> + Send + Sync + 'static,
565    {
566        let before_send = Some(Arc::new(before_send) as BeforeCallback<Event<'static>>);
567        Self {
568            before_send,
569            ..self
570        }
571    }
572
573    /// Sets the [callback](field@ClientOptions::before_breadcrumb) that is executed before adding
574    /// each breadcrumb.
575    #[inline]
576    pub fn before_breadcrumb<F>(self, before_breadcrumb: F) -> Self
577    where
578        F: Fn(Breadcrumb) -> Option<Breadcrumb> + Send + Sync + 'static,
579    {
580        let before_breadcrumb = Some(Arc::new(before_breadcrumb) as BeforeCallback<Breadcrumb>);
581        Self {
582            before_breadcrumb,
583            ..self
584        }
585    }
586
587    /// Sets the [callback](field@ClientOptions::before_send_log) that is executed before sending
588    /// each log.
589    #[cfg(feature = "logs")]
590    #[inline]
591    pub fn before_send_log<F>(self, before_send_log: F) -> Self
592    where
593        F: Fn(Log) -> Option<Log> + Send + Sync + 'static,
594    {
595        let before_send_log = Some(Arc::new(before_send_log) as BeforeCallback<Log>);
596        Self {
597            before_send_log,
598            ..self
599        }
600    }
601
602    /// Sets the [callback](field@ClientOptions::before_send_metric) that is executed before
603    /// sending each metric.
604    ///
605    /// This callback can modify a metric or return `None` to drop it.
606    #[cfg(feature = "metrics")]
607    #[inline]
608    pub fn before_send_metric<F>(self, before_send_metric: F) -> Self
609    where
610        F: Fn(Metric) -> Option<Metric> + Send + Sync + 'static,
611    {
612        let before_send_metric = Some(Arc::new(before_send_metric) as BeforeCallback<Metric>);
613        Self {
614            before_send_metric,
615            ..self
616        }
617    }
618
619    /// Sets the [transport](field@ClientOptions::transport) to use.
620    ///
621    /// This is typically either a function taking the client options by reference and returning a
622    /// transport, an `Arc<Transport>`, or the `DefaultTransportFactory`. Types that do not
623    /// implement [`TransportFactory`] use direct field assignment.
624    #[inline]
625    pub fn transport<T: TransportFactory + 'static>(self, transport: T) -> Self {
626        let transport = Some(Arc::new(transport) as Arc<dyn TransportFactory>);
627        Self { transport, ..self }
628    }
629
630    /// Sets the optional [HTTP proxy](field@ClientOptions::http_proxy) to use.
631    ///
632    /// This defaults to the `http_proxy` environment variable.
633    #[inline]
634    pub fn http_proxy<T>(self, http_proxy: T) -> Self
635    where
636        T: Into<Cow<'static, str>>,
637    {
638        let http_proxy = Some(http_proxy.into());
639        Self { http_proxy, ..self }
640    }
641
642    /// Sets the optional [HTTPS proxy](field@ClientOptions::https_proxy) to use.
643    ///
644    /// This defaults to the `HTTPS_PROXY` environment variable, or `http_proxy` if that one
645    /// exists.
646    #[inline]
647    pub fn https_proxy<T>(self, https_proxy: T) -> Self
648    where
649        T: Into<Cow<'static, str>>,
650    {
651        let https_proxy = Some(https_proxy.into());
652        Self {
653            https_proxy,
654            ..self
655        }
656    }
657
658    /// Sets the [shutdown drain timeout](field@ClientOptions::shutdown_timeout).
659    ///
660    /// Defaults to 2 seconds.
661    #[inline]
662    pub fn shutdown_timeout(self, shutdown_timeout: Duration) -> Self {
663        Self {
664            shutdown_timeout,
665            ..self
666        }
667    }
668
669    /// Sets the [maximum request body size](field@ClientOptions::max_request_body_size) to
670    /// capture.
671    ///
672    /// Controls the maximum size of an HTTP request body that can be captured when using HTTP
673    /// server integrations. Needs [`send_default_pii`](method@ClientOptions::send_default_pii) to
674    /// be enabled to have any effect. Defaults to [`MaxRequestBodySize::Medium`].
675    #[inline]
676    pub fn max_request_body_size(self, max_request_body_size: MaxRequestBodySize) -> Self {
677        Self {
678            max_request_body_size,
679            ..self
680        }
681    }
682
683    /// Deprecated. Setting [`enable_logs`](field@ClientOptions::enable_logs) to `false` only
684    /// disables automatic log capture by the log-capturing integrations (`log` and `tracing`
685    /// with the `logs` feature); it does not disable logs captured manually via
686    /// [`Hub::capture_log`](crate::Hub::capture_log) and the `logger_*` macros.
687    ///
688    /// To stop an integration from sending logs, use its own options to configure what it
689    /// captures. Alternatively, use [`Self::before_send_log`] to filter logs.
690    #[deprecated = "logs captured manually are always sent; only automatic capture by integrations respects this option"]
691    #[inline]
692    pub fn enable_logs(self, enable_logs: bool) -> Self {
693        Self {
694            #[expect(deprecated, reason = "need to set deprecated field")]
695            enable_logs,
696            ..self
697        }
698    }
699
700    /// This function is a no-op, as it sets the deprecated field
701    /// [`enable_metrics`](field@ClientOptions::enable_metrics). Metrics are always enabled.
702    ///
703    /// To stop sending metrics, simply remove any calls to our metrics APIs.
704    #[deprecated = "this function sets a no-op option"]
705    #[inline]
706    pub fn enable_metrics(self, enable_metrics: bool) -> Self {
707        Self {
708            #[expect(deprecated, reason = "need to set deprecated field")]
709            enable_metrics,
710            ..self
711        }
712    }
713
714    /// Enables or disables
715    /// [accepting invalid TLS certificates](field@ClientOptions::accept_invalid_certs).
716    ///
717    /// This introduces significant vulnerabilities, and should only be used as a last resort.
718    /// Defaults to `false`.
719    #[inline]
720    pub fn accept_invalid_certs(self, accept_invalid_certs: bool) -> Self {
721        Self {
722            accept_invalid_certs,
723            ..self
724        }
725    }
726
727    /// Enables or disables
728    /// [automatic session tracking](field@ClientOptions::auto_session_tracking).
729    ///
730    /// When enabled, a new "user-mode" session is started at `sentry::init` and persists for the
731    /// application lifetime. Defaults to `false`.
732    #[cfg(feature = "release-health")]
733    #[inline]
734    pub fn auto_session_tracking(self, auto_session_tracking: bool) -> Self {
735        Self {
736            auto_session_tracking,
737            ..self
738        }
739    }
740
741    /// Sets how [sessions are tracked](field@ClientOptions::session_mode).
742    ///
743    /// See [`SessionMode`] for the available modes. Defaults to [`SessionMode::Application`].
744    #[cfg(feature = "release-health")]
745    #[inline]
746    pub fn session_mode(self, session_mode: SessionMode) -> Self {
747        Self {
748            session_mode,
749            ..self
750        }
751    }
752
753    /// Sets the [user agent](field@ClientOptions::user_agent) that should be reported.
754    ///
755    /// Defaults to the SDK user agent.
756    #[inline]
757    pub fn user_agent<T>(self, user_agent: T) -> Self
758    where
759        T: Into<Cow<'static, str>>,
760    {
761        let user_agent = user_agent.into();
762        Self { user_agent, ..self }
763    }
764
765    /// Adds a configured integration to the options.
766    ///
767    /// # Examples
768    ///
769    /// ```
770    /// struct MyIntegration;
771    ///
772    /// impl sentry::Integration for MyIntegration {}
773    ///
774    /// let options = sentry::ClientOptions::new().add_integration(MyIntegration);
775    /// assert_eq!(options.integrations.len(), 1);
776    /// ```
777    #[inline]
778    pub fn add_integration<I: Integration>(mut self, integration: I) -> Self {
779        self.integrations.push(Arc::new(integration));
780        self
781    }
782}
783impl fmt::Debug for ClientOptions {
784    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
785        #[derive(Debug)]
786        struct BeforeSend;
787        let before_send = self.before_send.as_ref().map(|_| BeforeSend);
788        #[derive(Debug)]
789        struct BeforeBreadcrumb;
790        let before_breadcrumb = self.before_breadcrumb.as_ref().map(|_| BeforeBreadcrumb);
791        let before_send_log = {
792            #[derive(Debug)]
793            struct BeforeSendLog;
794            self.before_send_log.as_ref().map(|_| BeforeSendLog)
795        };
796        let before_send_metric = {
797            #[derive(Debug)]
798            struct BeforeSendMetric;
799            self.before_send_metric.as_ref().map(|_| BeforeSendMetric)
800        };
801        #[derive(Debug)]
802        struct TransportFactory;
803
804        let integrations: Vec<_> = self.integrations.iter().map(|i| i.name()).collect();
805
806        let mut debug_struct = f.debug_struct("ClientOptions");
807        debug_struct
808            .field("dsn", &self.dsn)
809            .field("debug", &self.debug)
810            .field("release", &self.release)
811            .field("environment", &self.environment)
812            .field("event_sampling_strategy", &self.event_sampling_strategy)
813            .field("traces_sampling_strategy", &self.traces_sampling_strategy)
814            .field("max_breadcrumbs", &self.max_breadcrumbs)
815            .field("attach_stacktrace", &self.attach_stacktrace)
816            .field("send_default_pii", &self.send_default_pii)
817            .field("server_name", &self.server_name)
818            .field("in_app_include", &self.in_app_include)
819            .field("in_app_exclude", &self.in_app_exclude)
820            .field("integrations", &integrations)
821            .field("default_integrations", &self.default_integrations)
822            .field("before_send", &before_send)
823            .field("before_breadcrumb", &before_breadcrumb)
824            .field("transport", &TransportFactory)
825            .field("http_proxy", &self.http_proxy)
826            .field("https_proxy", &self.https_proxy)
827            .field("shutdown_timeout", &self.shutdown_timeout)
828            .field("accept_invalid_certs", &self.accept_invalid_certs)
829            .field("auto_session_tracking", &self.auto_session_tracking)
830            .field("session_mode", &self.session_mode)
831            .field(
832                "enable_logs",
833                #[expect(deprecated, reason = "still need to debug-log this field")]
834                &self.enable_logs,
835            )
836            .field("before_send_log", &before_send_log)
837            .field(
838                "enable_metrics",
839                #[expect(deprecated, reason = "still need to debug-log this field")]
840                &self.enable_metrics,
841            )
842            .field("before_send_metric", &before_send_metric)
843            .field("org_id", &self.org_id)
844            .field("strict_trace_continuation", &self.strict_trace_continuation)
845            .field("user_agent", &self.user_agent)
846            .finish()
847    }
848}
849
850impl Default for ClientOptions {
851    fn default() -> ClientOptions {
852        ClientOptions {
853            dsn: None,
854            org_id: None,
855            strict_trace_continuation: false,
856            debug: false,
857            release: None,
858            environment: None,
859            event_sampling_strategy: Default::default(),
860            traces_sampling_strategy: Default::default(),
861            max_breadcrumbs: 100,
862            attach_stacktrace: false,
863            send_default_pii: false,
864            server_name: None,
865            in_app_include: vec![],
866            in_app_exclude: vec![],
867            integrations: vec![],
868            default_integrations: true,
869            before_send: None,
870            before_breadcrumb: None,
871            transport: None,
872            http_proxy: None,
873            https_proxy: None,
874            shutdown_timeout: Duration::from_secs(2),
875            accept_invalid_certs: false,
876            auto_session_tracking: false,
877            session_mode: SessionMode::Application,
878            user_agent: Cow::Borrowed(USER_AGENT),
879            max_request_body_size: MaxRequestBodySize::Medium,
880            #[expect(deprecated, reason = "still need to set deprecated fields")]
881            enable_logs: true,
882            before_send_log: None,
883            #[expect(deprecated, reason = "still need to set deprecated fields")]
884            enable_metrics: true,
885            before_send_metric: None,
886        }
887    }
888}
889
890impl<T: IntoDsn> From<(T, ClientOptions)> for ClientOptions {
891    fn from((into_dsn, mut opts): (T, ClientOptions)) -> ClientOptions {
892        opts.dsn = into_dsn.into_dsn().expect("invalid value for DSN");
893        opts
894    }
895}
896
897impl<T: IntoDsn> From<T> for ClientOptions {
898    fn from(into_dsn: T) -> ClientOptions {
899        ClientOptions {
900            dsn: into_dsn.into_dsn().expect("invalid value for DSN"),
901            ..ClientOptions::default()
902        }
903    }
904}