1 cfg_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 
180 cfg_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 }
189