Skip to content

Commit ed32cd1

Browse files
authored
task: add tests for tracing instrumentation of tasks (#6112)
Tokio is instrumented with traces which can be used to analyze the behavior of the runtime during execution or post-mortem. The instrumentation is optional. This is where tokio-console collections information. There are currently no tests for the instrumentation. In order to provide more stability to the instrumentation and prepare for future changes, tests are added to verify the current behavior. The tests are written using the `tracing-mock` crate. As this crate is still unreleased, a separate test create has been added under `tokio/tests` which is outside the workspace. This allows us to pull in both `tracing` and `tracing-mock` from the tracing repository on GitHub without affecting the rest of the tokio repository. This change adds initial tests for the task instrumentation. Further tests will be added in subsequent commits. Once `tracing-mock` is published on crates.io (tokio-rs/tracing#539), these tests can be moved in with the "normal" tokio integration tests. The decision to add these tests now is due to the release of `tracing-mock` taking a while, so it would be better to have tests while we wait.
1 parent 593dbf5 commit ed32cd1

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed

.github/workflows/ci.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ jobs:
4444
- test-workspace-all-features
4545
- test-integration-tests-per-feature
4646
- test-parking_lot
47+
- test-tracing-instrumentation
4748
- valgrind
4849
- test-unstable
4950
- miri
@@ -213,6 +214,34 @@ jobs:
213214
- name: Check tests with all features enabled
214215
run: cargo check --workspace --all-features --tests
215216

217+
test-tracing-instrumentation:
218+
# These tests use the as-yet unpublished `tracing-mock` crate to test the
219+
# tracing instrumentation present in Tokio. As such they are placed in
220+
# their own test crate outside of the workspace.
221+
needs: basics
222+
name: test tokio instrumentation
223+
runs-on: ubuntu-latest
224+
steps:
225+
- uses: actions/checkout@v3
226+
- name: Install Rust ${{ env.rust_stable }}
227+
uses: dtolnay/rust-toolchain@stable
228+
with:
229+
toolchain: ${{ env.rust_stable }}
230+
- name: Install cargo-nextest
231+
uses: taiki-e/install-action@v2
232+
with:
233+
tool: cargo-nextest
234+
235+
- uses: Swatinem/rust-cache@v2
236+
237+
- name: test tracing-instrumentation
238+
run: |
239+
set -euxo pipefail
240+
cargo nextest run
241+
working-directory: tokio/tests/tracing-instrumentation
242+
env:
243+
RUSTFLAGS: --cfg tokio_unstable -Dwarnings
244+
216245
valgrind:
217246
name: valgrind
218247
needs: basics
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "tracing-instrumentation"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
8+
[dev-dependencies]
9+
futures = { version = "0.3.0", features = ["async-await"] }
10+
tokio = { version = "1.33.0", path = "../..", features = ["full", "tracing"] }
11+
tracing = { version = "0.1.40", git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" }
12+
tracing-mock = { version = "0.1.0", git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" }
13+
14+
[patch.crates-io]
15+
tracing = { git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" }
16+
17+
[workspace]
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//! Tests for task instrumentation.
2+
//!
3+
//! These tests ensure that the instrumentation for task spawning and task
4+
//! lifecycles is correct.
5+
6+
use tokio::task;
7+
use tracing_mock::{expect, span::NewSpan, subscriber};
8+
9+
#[tokio::test]
10+
async fn task_spawn_creates_span() {
11+
let task_span = expect::span()
12+
.named("runtime.spawn")
13+
.with_target("tokio::task");
14+
15+
let (subscriber, handle) = subscriber::mock()
16+
.new_span(task_span.clone())
17+
.enter(task_span.clone())
18+
.exit(task_span.clone())
19+
// The task span is entered once more when it gets dropped
20+
.enter(task_span.clone())
21+
.exit(task_span.clone())
22+
.drop_span(task_span)
23+
.run_with_handle();
24+
25+
{
26+
let _guard = tracing::subscriber::set_default(subscriber);
27+
tokio::spawn(futures::future::ready(()))
28+
.await
29+
.expect("failed to await join handle");
30+
}
31+
32+
handle.assert_finished();
33+
}
34+
35+
#[tokio::test]
36+
async fn task_spawn_loc_file_recorded() {
37+
let task_span = expect::span()
38+
.named("runtime.spawn")
39+
.with_target("tokio::task")
40+
.with_field(expect::field("loc.file").with_value(&file!()));
41+
42+
let (subscriber, handle) = subscriber::mock().new_span(task_span).run_with_handle();
43+
44+
{
45+
let _guard = tracing::subscriber::set_default(subscriber);
46+
47+
tokio::spawn(futures::future::ready(()))
48+
.await
49+
.expect("failed to await join handle");
50+
}
51+
52+
handle.assert_finished();
53+
}
54+
55+
#[tokio::test]
56+
async fn task_builder_name_recorded() {
57+
let task_span = expect_task_named("test-task");
58+
59+
let (subscriber, handle) = subscriber::mock().new_span(task_span).run_with_handle();
60+
61+
{
62+
let _guard = tracing::subscriber::set_default(subscriber);
63+
task::Builder::new()
64+
.name("test-task")
65+
.spawn(futures::future::ready(()))
66+
.unwrap()
67+
.await
68+
.expect("failed to await join handle");
69+
}
70+
71+
handle.assert_finished();
72+
}
73+
74+
#[tokio::test]
75+
async fn task_builder_loc_file_recorded() {
76+
let task_span = expect::span()
77+
.named("runtime.spawn")
78+
.with_target("tokio::task")
79+
.with_field(expect::field("loc.file").with_value(&file!()));
80+
81+
let (subscriber, handle) = subscriber::mock().new_span(task_span).run_with_handle();
82+
83+
{
84+
let _guard = tracing::subscriber::set_default(subscriber);
85+
86+
task::Builder::new()
87+
.spawn(futures::future::ready(()))
88+
.unwrap()
89+
.await
90+
.expect("failed to await join handle");
91+
}
92+
93+
handle.assert_finished();
94+
}
95+
96+
/// Expect a task with name
97+
///
98+
/// This is a convenience function to create the expectation for a new task
99+
/// with the `task.name` field set to the provided name.
100+
fn expect_task_named(name: &str) -> NewSpan {
101+
expect::span()
102+
.named("runtime.spawn")
103+
.with_target("tokio::task")
104+
.with_field(
105+
expect::field("task.name").with_value(&tracing::field::debug(format_args!("{}", name))),
106+
)
107+
}

0 commit comments

Comments
 (0)