1 use std::convert::Infallible;
2 use std::{future::Future, pin::Pin, sync::Arc};
3
4 use tracing::subscriber::with_default;
5 use tracing_attributes::instrument;
6 use tracing_mock::{expect, subscriber};
7 use tracing_test::{block_on_future, PollN};
8
9 #[instrument]
test_async_fn(polls: usize) -> Result<(), ()>10 async fn test_async_fn(polls: usize) -> Result<(), ()> {
11 let future = PollN::new_ok(polls);
12 tracing::trace!(awaiting = true);
13 future.await
14 }
15
16 // Reproduces a compile error when returning an `impl Trait` from an
17 // instrumented async fn (see https://github.com/tokio-rs/tracing/issues/1615)
18 #[allow(dead_code)] // this is just here to test whether it compiles.
19 #[instrument]
test_ret_impl_trait(n: i32) -> Result<impl Iterator<Item = i32>, ()>20 async fn test_ret_impl_trait(n: i32) -> Result<impl Iterator<Item = i32>, ()> {
21 Ok((0..10).filter(move |x| *x < n))
22 }
23
24 // Reproduces a compile error when returning an `impl Trait` from an
25 // instrumented async fn (see https://github.com/tokio-rs/tracing/issues/1615)
26 #[allow(dead_code)] // this is just here to test whether it compiles.
27 #[instrument(err)]
test_ret_impl_trait_err(n: i32) -> Result<impl Iterator<Item = i32>, &'static str>28 async fn test_ret_impl_trait_err(n: i32) -> Result<impl Iterator<Item = i32>, &'static str> {
29 Ok((0..10).filter(move |x| *x < n))
30 }
31
32 #[instrument]
test_async_fn_empty()33 async fn test_async_fn_empty() {}
34
35 #[instrument]
test_async_unsafe_fn_empty()36 async unsafe fn test_async_unsafe_fn_empty() {}
37
38 // Reproduces a compile error when an instrumented function body contains inner
39 // attributes (https://github.com/tokio-rs/tracing/issues/2294).
40 #[deny(unused_variables)]
41 #[instrument]
repro_async_2294()42 async fn repro_async_2294() {
43 #![allow(unused_variables)]
44 let i = 42;
45 }
46
47 // Reproduces https://github.com/tokio-rs/tracing/issues/1613
48 #[instrument]
49 // LOAD-BEARING `#[rustfmt::skip]`! This is necessary to reproduce the bug;
50 // with the rustfmt-generated formatting, the lint will not be triggered!
51 #[rustfmt::skip]
52 #[deny(clippy::suspicious_else_formatting)]
repro_1613(var: bool)53 async fn repro_1613(var: bool) {
54 println!(
55 "{}",
56 if var { "true" } else { "false" }
57 );
58 }
59
60 // Reproduces https://github.com/tokio-rs/tracing/issues/1613
61 // and https://github.com/rust-lang/rust-clippy/issues/7760
62 #[instrument]
63 #[deny(clippy::suspicious_else_formatting)]
repro_1613_2()64 async fn repro_1613_2() {
65 // hello world
66 // else
67 }
68
69 // Reproduces https://github.com/tokio-rs/tracing/issues/1831
70 #[allow(dead_code)] // this is just here to test whether it compiles.
71 #[instrument]
72 #[deny(unused_braces)]
repro_1831() -> Pin<Box<dyn Future<Output = ()>>>73 fn repro_1831() -> Pin<Box<dyn Future<Output = ()>>> {
74 Box::pin(async move {})
75 }
76
77 // This replicates the pattern used to implement async trait methods on nightly using the
78 // `type_alias_impl_trait` feature
79 #[allow(dead_code)] // this is just here to test whether it compiles.
80 #[instrument(ret, err)]
81 #[deny(unused_braces)]
82 #[allow(clippy::manual_async_fn)]
repro_1831_2() -> impl Future<Output = Result<(), Infallible>>83 fn repro_1831_2() -> impl Future<Output = Result<(), Infallible>> {
84 async { Ok(()) }
85 }
86
87 #[test]
async_fn_only_enters_for_polls()88 fn async_fn_only_enters_for_polls() {
89 let (subscriber, handle) = subscriber::mock()
90 .new_span(expect::span().named("test_async_fn"))
91 .enter(expect::span().named("test_async_fn"))
92 .event(expect::event().with_fields(expect::field("awaiting").with_value(&true)))
93 .exit(expect::span().named("test_async_fn"))
94 .enter(expect::span().named("test_async_fn"))
95 .exit(expect::span().named("test_async_fn"))
96 .enter(expect::span().named("test_async_fn"))
97 .exit(expect::span().named("test_async_fn"))
98 .drop_span(expect::span().named("test_async_fn"))
99 .only()
100 .run_with_handle();
101 with_default(subscriber, || {
102 block_on_future(async { test_async_fn(2).await }).unwrap();
103 });
104 handle.assert_finished();
105 }
106
107 #[test]
async_fn_nested()108 fn async_fn_nested() {
109 #[instrument]
110 async fn test_async_fns_nested() {
111 test_async_fns_nested_other().await
112 }
113
114 #[instrument]
115 async fn test_async_fns_nested_other() {
116 tracing::trace!(nested = true);
117 }
118
119 let span = expect::span().named("test_async_fns_nested");
120 let span2 = expect::span().named("test_async_fns_nested_other");
121 let (subscriber, handle) = subscriber::mock()
122 .new_span(span.clone())
123 .enter(span.clone())
124 .new_span(span2.clone())
125 .enter(span2.clone())
126 .event(expect::event().with_fields(expect::field("nested").with_value(&true)))
127 .exit(span2.clone())
128 .enter(span2.clone())
129 .exit(span2.clone())
130 .drop_span(span2)
131 .exit(span.clone())
132 .enter(span.clone())
133 .exit(span.clone())
134 .drop_span(span)
135 .only()
136 .run_with_handle();
137
138 with_default(subscriber, || {
139 block_on_future(async { test_async_fns_nested().await });
140 });
141
142 handle.assert_finished();
143 }
144
145 #[test]
async_fn_with_async_trait()146 fn async_fn_with_async_trait() {
147 use async_trait::async_trait;
148
149 // test the correctness of the metadata obtained by #[instrument]
150 // (function name, functions parameters) when async-trait is used
151 #[async_trait]
152 pub trait TestA {
153 async fn foo(&mut self, v: usize);
154 }
155
156 // test nesting of async fns with aync-trait
157 #[async_trait]
158 pub trait TestB {
159 async fn bar(&self);
160 }
161
162 // test skip(self) with async-await
163 #[async_trait]
164 pub trait TestC {
165 async fn baz(&self);
166 }
167
168 #[derive(Debug)]
169 struct TestImpl(usize);
170
171 #[async_trait]
172 impl TestA for TestImpl {
173 #[instrument]
174 async fn foo(&mut self, v: usize) {
175 self.baz().await;
176 self.0 = v;
177 self.bar().await
178 }
179 }
180
181 #[async_trait]
182 impl TestB for TestImpl {
183 #[instrument]
184 async fn bar(&self) {
185 tracing::trace!(val = self.0);
186 }
187 }
188
189 #[async_trait]
190 impl TestC for TestImpl {
191 #[instrument(skip(self))]
192 async fn baz(&self) {
193 tracing::trace!(val = self.0);
194 }
195 }
196
197 let span = expect::span().named("foo");
198 let span2 = expect::span().named("bar");
199 let span3 = expect::span().named("baz");
200 let (subscriber, handle) = subscriber::mock()
201 .new_span(
202 span.clone()
203 .with_fields(expect::field("self"))
204 .with_fields(expect::field("v")),
205 )
206 .enter(span.clone())
207 .new_span(span3.clone())
208 .enter(span3.clone())
209 .event(expect::event().with_fields(expect::field("val").with_value(&2u64)))
210 .exit(span3.clone())
211 .enter(span3.clone())
212 .exit(span3.clone())
213 .drop_span(span3)
214 .new_span(span2.clone().with_fields(expect::field("self")))
215 .enter(span2.clone())
216 .event(expect::event().with_fields(expect::field("val").with_value(&5u64)))
217 .exit(span2.clone())
218 .enter(span2.clone())
219 .exit(span2.clone())
220 .drop_span(span2)
221 .exit(span.clone())
222 .enter(span.clone())
223 .exit(span.clone())
224 .drop_span(span)
225 .only()
226 .run_with_handle();
227
228 with_default(subscriber, || {
229 let mut test = TestImpl(2);
230 block_on_future(async { test.foo(5).await });
231 });
232
233 handle.assert_finished();
234 }
235
236 #[test]
async_fn_with_async_trait_and_fields_expressions()237 fn async_fn_with_async_trait_and_fields_expressions() {
238 use async_trait::async_trait;
239
240 #[async_trait]
241 pub trait Test {
242 async fn call(&mut self, v: usize);
243 }
244
245 #[derive(Clone, Debug)]
246 struct TestImpl;
247
248 impl TestImpl {
249 fn foo(&self) -> usize {
250 42
251 }
252 }
253
254 #[async_trait]
255 impl Test for TestImpl {
256 // check that self is correctly handled, even when using async_trait
257 #[instrument(fields(val=self.foo(), val2=Self::clone(self).foo(), test=%_v+5))]
258 async fn call(&mut self, _v: usize) {}
259 }
260
261 let span = expect::span().named("call");
262 let (subscriber, handle) = subscriber::mock()
263 .new_span(
264 span.clone().with_fields(
265 expect::field("_v")
266 .with_value(&5usize)
267 .and(expect::field("test").with_value(&tracing::field::debug(10)))
268 .and(expect::field("val").with_value(&42u64))
269 .and(expect::field("val2").with_value(&42u64)),
270 ),
271 )
272 .enter(span.clone())
273 .exit(span.clone())
274 .enter(span.clone())
275 .exit(span.clone())
276 .drop_span(span)
277 .only()
278 .run_with_handle();
279
280 with_default(subscriber, || {
281 block_on_future(async { TestImpl.call(5).await });
282 });
283
284 handle.assert_finished();
285 }
286
287 #[test]
async_fn_with_async_trait_and_fields_expressions_with_generic_parameter()288 fn async_fn_with_async_trait_and_fields_expressions_with_generic_parameter() {
289 use async_trait::async_trait;
290
291 #[async_trait]
292 pub trait Test {
293 async fn call();
294 async fn call_with_self(&self);
295 async fn call_with_mut_self(&mut self);
296 }
297
298 #[derive(Clone, Debug)]
299 struct TestImpl;
300
301 // we also test sync functions that return futures, as they should be handled just like
302 // async-trait (>= 0.1.44) functions
303 impl TestImpl {
304 #[instrument(fields(Self=std::any::type_name::<Self>()))]
305 fn sync_fun(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
306 let val = self.clone();
307 Box::pin(async move {
308 let _ = val;
309 })
310 }
311 }
312
313 #[async_trait]
314 impl Test for TestImpl {
315 // instrumenting this is currently not possible, see https://github.com/tokio-rs/tracing/issues/864#issuecomment-667508801
316 //#[instrument(fields(Self=std::any::type_name::<Self>()))]
317 async fn call() {}
318
319 #[instrument(fields(Self=std::any::type_name::<Self>()))]
320 async fn call_with_self(&self) {
321 self.sync_fun().await;
322 }
323
324 #[instrument(fields(Self=std::any::type_name::<Self>()))]
325 async fn call_with_mut_self(&mut self) {}
326 }
327
328 //let span = span::mock().named("call");
329 let span2 = expect::span().named("call_with_self");
330 let span3 = expect::span().named("call_with_mut_self");
331 let span4 = expect::span().named("sync_fun");
332 let (subscriber, handle) = subscriber::mock()
333 /*.new_span(span.clone()
334 .with_fields(
335 expect::field("Self").with_value(&"TestImpler")))
336 .enter(span.clone())
337 .exit(span.clone())
338 .drop_span(span)*/
339 .new_span(
340 span2
341 .clone()
342 .with_fields(expect::field("Self").with_value(&std::any::type_name::<TestImpl>())),
343 )
344 .enter(span2.clone())
345 .new_span(
346 span4
347 .clone()
348 .with_fields(expect::field("Self").with_value(&std::any::type_name::<TestImpl>())),
349 )
350 .enter(span4.clone())
351 .exit(span4.clone())
352 .enter(span4.clone())
353 .exit(span4)
354 .exit(span2.clone())
355 .enter(span2.clone())
356 .exit(span2.clone())
357 .drop_span(span2)
358 .new_span(
359 span3
360 .clone()
361 .with_fields(expect::field("Self").with_value(&std::any::type_name::<TestImpl>())),
362 )
363 .enter(span3.clone())
364 .exit(span3.clone())
365 .enter(span3.clone())
366 .exit(span3.clone())
367 .drop_span(span3)
368 .only()
369 .run_with_handle();
370
371 with_default(subscriber, || {
372 block_on_future(async {
373 TestImpl::call().await;
374 TestImpl.call_with_self().await;
375 TestImpl.call_with_mut_self().await
376 });
377 });
378
379 handle.assert_finished();
380 }
381
382 #[test]
out_of_scope_fields()383 fn out_of_scope_fields() {
384 // Reproduces tokio-rs/tracing#1296
385
386 struct Thing {
387 metrics: Arc<()>,
388 }
389
390 impl Thing {
391 #[instrument(skip(self, _req), fields(app_id))]
392 fn call(&mut self, _req: ()) -> Pin<Box<dyn Future<Output = Arc<()>> + Send + Sync>> {
393 // ...
394 let metrics = self.metrics.clone();
395 // ...
396 Box::pin(async move {
397 // ...
398 metrics // cannot find value `metrics` in this scope
399 })
400 }
401 }
402
403 let span = expect::span().named("call");
404 let (subscriber, handle) = subscriber::mock()
405 .new_span(span.clone())
406 .enter(span.clone())
407 .exit(span.clone())
408 .enter(span.clone())
409 .exit(span.clone())
410 .drop_span(span)
411 .only()
412 .run_with_handle();
413
414 with_default(subscriber, || {
415 block_on_future(async {
416 let mut my_thing = Thing {
417 metrics: Arc::new(()),
418 };
419 my_thing.call(()).await;
420 });
421 });
422
423 handle.assert_finished();
424 }
425
426 #[test]
manual_impl_future()427 fn manual_impl_future() {
428 #[allow(clippy::manual_async_fn)]
429 #[instrument]
430 fn manual_impl_future() -> impl Future<Output = ()> {
431 async {
432 tracing::trace!(poll = true);
433 }
434 }
435
436 let span = expect::span().named("manual_impl_future");
437 let poll_event = || expect::event().with_fields(expect::field("poll").with_value(&true));
438
439 let (subscriber, handle) = subscriber::mock()
440 // await manual_impl_future
441 .new_span(span.clone())
442 .enter(span.clone())
443 .event(poll_event())
444 .exit(span.clone())
445 .enter(span.clone())
446 .exit(span.clone())
447 .drop_span(span)
448 .only()
449 .run_with_handle();
450
451 with_default(subscriber, || {
452 block_on_future(async {
453 manual_impl_future().await;
454 });
455 });
456
457 handle.assert_finished();
458 }
459
460 #[test]
manual_box_pin()461 fn manual_box_pin() {
462 #[instrument]
463 fn manual_box_pin() -> Pin<Box<dyn Future<Output = ()>>> {
464 Box::pin(async {
465 tracing::trace!(poll = true);
466 })
467 }
468
469 let span = expect::span().named("manual_box_pin");
470 let poll_event = || expect::event().with_fields(expect::field("poll").with_value(&true));
471
472 let (subscriber, handle) = subscriber::mock()
473 // await manual_box_pin
474 .new_span(span.clone())
475 .enter(span.clone())
476 .event(poll_event())
477 .exit(span.clone())
478 .enter(span.clone())
479 .exit(span.clone())
480 .drop_span(span)
481 .only()
482 .run_with_handle();
483
484 with_default(subscriber, || {
485 block_on_future(async {
486 manual_box_pin().await;
487 });
488 });
489
490 handle.assert_finished();
491 }
492