sentry_core/
futures.rs
1use std::future::Future;
2use std::pin::Pin;
3use std::sync::Arc;
4use std::task::{Context, Poll};
5
6use crate::Hub;
7
8#[derive(Debug)]
16pub struct SentryFuture<F> {
17 hub: Arc<Hub>,
18 future: F,
19}
20
21impl<F> SentryFuture<F> {
22 pub fn new(hub: Arc<Hub>, future: F) -> Self {
24 Self { hub, future }
25 }
26}
27
28impl<F> Future for SentryFuture<F>
29where
30 F: Future,
31{
32 type Output = F::Output;
33
34 fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
35 let hub = self.hub.clone();
36 let future = unsafe { self.map_unchecked_mut(|s| &mut s.future) };
38 #[cfg(feature = "client")]
39 {
40 let _guard = crate::hub_impl::SwitchGuard::new(hub);
41 future.poll(cx)
42 }
43 #[cfg(not(feature = "client"))]
44 {
45 let _ = hub;
46 future.poll(cx)
47 }
48 }
49}
50
51pub trait SentryFutureExt: Sized {
53 fn bind_hub<H>(self, hub: H) -> SentryFuture<Self>
57 where
58 H: Into<Arc<Hub>>,
59 {
60 SentryFuture {
61 future: self,
62 hub: hub.into(),
63 }
64 }
65}
66
67impl<F> SentryFutureExt for F where F: Future {}
68
69#[cfg(all(test, feature = "test"))]
70mod tests {
71 use crate::test::with_captured_events;
72 use crate::{capture_message, configure_scope, Hub, Level, SentryFutureExt};
73 use tokio::runtime::Runtime;
74
75 #[test]
76 fn test_futures() {
77 let mut events = with_captured_events(|| {
78 let runtime = Runtime::new().unwrap();
79
80 runtime.block_on(async {
82 let task1 = async {
83 configure_scope(|scope| scope.set_transaction(Some("transaction1")));
84 capture_message("oh hai from 1", Level::Info);
85 }
86 .bind_hub(Hub::new_from_top(Hub::current()));
87 let task1 = tokio::task::spawn(task1);
88
89 let task2 = async {
90 configure_scope(|scope| scope.set_transaction(Some("transaction2")));
91 capture_message("oh hai from 2", Level::Info);
92 }
93 .bind_hub(Hub::new_from_top(Hub::current()));
94 let task2 = tokio::task::spawn(task2);
95
96 task1.await.unwrap();
97 task2.await.unwrap();
98 });
99
100 capture_message("oh hai from outside", Level::Info);
101 });
102
103 events.sort_by(|a, b| a.transaction.cmp(&b.transaction));
104 assert_eq!(events.len(), 3);
105 assert_eq!(events[1].transaction, Some("transaction1".into()));
106 assert_eq!(events[2].transaction, Some("transaction2".into()));
107 }
108}