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