tokio/util/
trace.rs

1cfg_rt! {
2    use std::marker::PhantomData;
3
4    #[derive(Copy, Clone)]
5    pub(crate) struct SpawnMeta<'a> {
6        /// The name of the task
7        #[cfg(all(tokio_unstable, feature = "tracing"))]
8        pub(crate) name: Option<&'a str>,
9        /// The original size of the future or function being spawned
10        #[cfg(all(tokio_unstable, feature = "tracing"))]
11        pub(crate) original_size: usize,
12        _pd: PhantomData<&'a ()>,
13    }
14
15    impl<'a> SpawnMeta<'a> {
16        /// Create new spawn meta with a name and original size (before possible auto-boxing)
17        #[cfg(all(tokio_unstable, feature = "tracing"))]
18        pub(crate) fn new(name: Option<&'a str>, original_size: usize) -> Self {
19            Self {
20                name,
21                original_size,
22                _pd: PhantomData,
23            }
24        }
25
26        /// Create a new unnamed spawn meta with the original size (before possible auto-boxing)
27        pub(crate) fn new_unnamed(original_size: usize) -> Self {
28            #[cfg(not(all(tokio_unstable, feature = "tracing")))]
29            let _original_size = original_size;
30
31            Self {
32                #[cfg(all(tokio_unstable, feature = "tracing"))]
33                name: None,
34                #[cfg(all(tokio_unstable, feature = "tracing"))]
35                original_size,
36                _pd: PhantomData,
37            }
38        }
39    }
40
41    cfg_trace! {
42        use core::{
43            pin::Pin,
44            task::{Context, Poll},
45        };
46        use pin_project_lite::pin_project;
47        use std::mem;
48        use std::future::Future;
49        use tracing::instrument::Instrument;
50        pub(crate) use tracing::instrument::Instrumented;
51
52        #[inline]
53        #[track_caller]
54        pub(crate) fn task<F>(task: F, kind: &'static str, meta: SpawnMeta<'_>, id: u64) -> Instrumented<F> {
55            #[track_caller]
56            fn get_span(kind: &'static str, spawn_meta: SpawnMeta<'_>, id: u64, task_size: usize) -> tracing::Span {
57                let location = std::panic::Location::caller();
58                let original_size = if spawn_meta.original_size != task_size {
59                    Some(spawn_meta.original_size)
60                } else {
61                    None
62                };
63                tracing::trace_span!(
64                    target: "tokio::task",
65                    parent: None,
66                    "runtime.spawn",
67                    %kind,
68                    task.name = %spawn_meta.name.unwrap_or_default(),
69                    task.id = id,
70                    original_size.bytes = original_size,
71                    size.bytes = task_size,
72                    loc.file = location.file(),
73                    loc.line = location.line(),
74                    loc.col = location.column(),
75                )
76            }
77            use tracing::instrument::Instrument;
78            let span = get_span(kind, meta, id, mem::size_of::<F>());
79            task.instrument(span)
80        }
81
82        #[inline]
83        #[track_caller]
84        pub(crate) fn blocking_task<Fn, Fut>(task: Fut, spawn_meta: SpawnMeta<'_>, id: u64) -> Instrumented<Fut> {
85            let location = std::panic::Location::caller();
86
87            let fn_size = mem::size_of::<Fn>();
88            let original_size = if spawn_meta.original_size != fn_size {
89                Some(spawn_meta.original_size)
90            } else {
91                None
92            };
93
94            let span = tracing::trace_span!(
95                target: "tokio::task::blocking",
96                "runtime.spawn",
97                kind = %"blocking",
98                task.name = %spawn_meta.name.unwrap_or_default(),
99                task.id = id,
100                "fn" = %std::any::type_name::<Fn>(),
101                original_size.bytes = original_size,
102                size.bytes = fn_size,
103                loc.file = location.file(),
104                loc.line = location.line(),
105                loc.col = location.column(),
106            );
107            task.instrument(span)
108
109        }
110
111        pub(crate) fn async_op<P,F>(inner: P, resource_span: tracing::Span, source: &str, poll_op_name: &'static str, inherits_child_attrs: bool) -> InstrumentedAsyncOp<F>
112        where P: FnOnce() -> F {
113            resource_span.in_scope(|| {
114                let async_op_span = tracing::trace_span!("runtime.resource.async_op", source = source, inherits_child_attrs = inherits_child_attrs);
115                let enter = async_op_span.enter();
116                let async_op_poll_span = tracing::trace_span!("runtime.resource.async_op.poll");
117                let inner = inner();
118                drop(enter);
119                let tracing_ctx = AsyncOpTracingCtx {
120                    async_op_span,
121                    async_op_poll_span,
122                    resource_span: resource_span.clone(),
123                };
124                InstrumentedAsyncOp {
125                    inner,
126                    tracing_ctx,
127                    poll_op_name,
128                }
129            })
130        }
131
132        #[derive(Debug, Clone)]
133        pub(crate) struct AsyncOpTracingCtx {
134            pub(crate) async_op_span: tracing::Span,
135            pub(crate) async_op_poll_span: tracing::Span,
136            pub(crate) resource_span: tracing::Span,
137        }
138
139
140        pin_project! {
141            #[derive(Debug, Clone)]
142            pub(crate) struct InstrumentedAsyncOp<F> {
143                #[pin]
144                pub(crate) inner: F,
145                pub(crate) tracing_ctx: AsyncOpTracingCtx,
146                pub(crate) poll_op_name: &'static str
147            }
148        }
149
150        impl<F: Future> Future for InstrumentedAsyncOp<F> {
151            type Output = F::Output;
152
153            fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
154                let this = self.project();
155                let poll_op_name = &*this.poll_op_name;
156                let _res_enter = this.tracing_ctx.resource_span.enter();
157                let _async_op_enter = this.tracing_ctx.async_op_span.enter();
158                let _async_op_poll_enter = this.tracing_ctx.async_op_poll_span.enter();
159                trace_poll_op!(poll_op_name, this.inner.poll(cx))
160            }
161        }
162    }
163
164    cfg_not_trace! {
165        #[inline]
166        pub(crate) fn task<F>(task: F, _kind: &'static str, _meta: SpawnMeta<'_>, _id: u64) -> F {
167            // nop
168            task
169        }
170
171        #[inline]
172        pub(crate) fn blocking_task<Fn, Fut>(task: Fut, _spawn_meta: SpawnMeta<'_>, _id: u64) -> Fut {
173            let _ = PhantomData::<&Fn>;
174            // nop
175            task
176        }
177    }
178}
179
180cfg_time! {
181    #[track_caller]
182    pub(crate) fn caller_location() -> Option<&'static std::panic::Location<'static>> {
183        #[cfg(all(tokio_unstable, feature = "tracing"))]
184        return Some(std::panic::Location::caller());
185        #[cfg(not(all(tokio_unstable, feature = "tracing")))]
186        None
187    }
188}