Skip to main content

sentry_core/
clientoptions.rs

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