sentry_core/transport/mod.rs
1use std::sync::Arc;
2use std::time::Duration;
3
4use crate::{ClientOptions, Envelope};
5
6mod options;
7
8pub use self::options::TransportOptions;
9
10/// The trait for transports.
11///
12/// A transport is responsible for sending events to Sentry. Custom implementations
13/// can be created to use a different abstraction to send events. This is for instance
14/// used for the test system.
15pub trait Transport: Send + Sync + 'static {
16 /// Sends an [`Envelope`].
17 ///
18 /// [`Envelope`]: struct.Envelope.html
19 fn send_envelope(&self, envelope: Envelope);
20
21 /// Flushes the transport queue if there is one.
22 ///
23 /// If the queue was successfully drained, the return value should be
24 /// `true` or `false` if events were left in it.
25 fn flush(&self, timeout: Duration) -> bool {
26 let _timeout = timeout;
27 true
28 }
29
30 /// Instructs the Transport to shut down.
31 fn shutdown(&self, timeout: Duration) -> bool {
32 self.flush(timeout)
33 }
34}
35
36/// A factory creating transport instances.
37///
38/// Because options are potentially reused between different clients the
39/// [`ClientOptions`] do not actually contain a transport but a factory object that
40/// can create transports instead.
41///
42/// This factory has two methods. Although both methods have default implementations, the default
43/// implementations call each other, so to avoid an infinitely recursive loop, types implementing
44/// this trait **must implement at least one of these methods**. We recommend that implementors
45/// implement only [`TransportFactory::create_transport_with_options`] because the other method,
46/// [`TransportFactory::create_transport`] only exists for backwards compatibility.
47///
48/// Both factory methods create a new transport wrapped in an [`Arc`]. Because transports can be
49/// wrapped in `Arc`s and those are clonable, `Arc<Transport>` is also a valid transport factory.
50/// This for instance lets you put a `Arc<TestTransport>` directly into the options.
51pub trait TransportFactory: Send + Sync {
52 /// Create a transport with the given `options`.
53 ///
54 /// Although a default implementation is provided for this trait method, we recommend that all
55 /// custom transport factories implement this method, as it is the way the SDK constructs the
56 /// transport. The default implementaton calls [`TransportFactory::create_transport`] as a
57 /// fallback.
58 fn create_transport_with_options(&self, options: TransportOptions) -> Arc<dyn Transport> {
59 #[expect(deprecated, reason = "need to call deprecated method for back-compat")]
60 self.create_transport(&options.into_client_options())
61 }
62
63 /// The legacy method for creating a transport.
64 ///
65 /// This method exists for backwards compatiblity with custom transport factories, which were
66 /// created before [`TransportFactory::create_transport_with_options`] was added, and thus only
67 /// implement this method.
68 ///
69 /// New custom transport factories **should not** implement this method, as it is not called
70 /// from the SDK. A sensible default implementation, which forwards to
71 /// [`TransportFactory::create_transport_with_options`] is provided.
72 #[deprecated = "use and implement `create_transport_with_options` instead"]
73 fn create_transport(&self, options: &ClientOptions) -> Arc<dyn Transport> {
74 TransportOptions::try_from_client_options(options).map_or_else(
75 || {
76 let no_op: Arc<dyn Transport> = Arc::new(NoOpTransport);
77 no_op
78 },
79 |options| self.create_transport_with_options(options),
80 )
81 }
82}
83
84/// A no-op transport.
85///
86/// This is returned by [`TransportFactory::create_transport`] when called without a `dsn` in the
87/// [`ClientOptions`], rendering the transport disabled.
88struct NoOpTransport;
89
90/// This implementor is **deprecated**, as the closure is used as the deprecated
91/// [`TransportFactory::create_transport`] method.
92///
93/// Use or create a [`TransportFactory`] which provides
94/// [`TransportFactory::create_transport_with_options`], instead.
95impl<F> TransportFactory for F
96where
97 F: Fn(&ClientOptions) -> Arc<dyn Transport> + Clone + Send + Sync + 'static,
98{
99 fn create_transport(&self, options: &ClientOptions) -> Arc<dyn Transport> {
100 (*self)(options)
101 }
102}
103
104impl<T: Transport> Transport for Arc<T> {
105 fn send_envelope(&self, envelope: Envelope) {
106 (**self).send_envelope(envelope)
107 }
108
109 fn shutdown(&self, timeout: Duration) -> bool {
110 (**self).shutdown(timeout)
111 }
112}
113
114impl<T: Transport> TransportFactory for Arc<T> {
115 fn create_transport_with_options(&self, _: TransportOptions) -> Arc<dyn Transport> {
116 self.clone()
117 }
118}
119
120impl Transport for NoOpTransport {
121 fn send_envelope(&self, envelope: Envelope) {
122 let _ = envelope;
123 }
124}