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