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