Skip to content

Commit 1cc5fdb

Browse files
committed
task: add tests for tracing instrumentation of tasks
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 58acb56 commit 1cc5fdb

File tree

3 files changed

+180
-27
lines changed

3 files changed

+180
-27
lines changed

.github/workflows/ci.yml

+56-27
Original file line numberDiff line numberDiff line change
@@ -41,34 +41,35 @@ jobs:
4141
runs-on: ubuntu-latest
4242
needs:
4343
- test-tokio-full
44-
- test-workspace-all-features
45-
- test-integration-tests-per-feature
46-
- test-parking_lot
47-
- valgrind
44+
# - test-workspace-all-features
45+
# - test-integration-tests-per-feature
46+
# - test-parking_lot
47+
- test-tracing-instrumentation
48+
# - valgrind
4849
- test-unstable
49-
- miri
50-
- asan
51-
- cross-check
52-
- cross-test-with-parking_lot
53-
- cross-test-without-parking_lot
54-
- no-atomic-u64-test
55-
- no-atomic-u64-check
56-
- features
57-
- minrust
58-
- minimal-versions
59-
- fmt
60-
- clippy
61-
- docs
62-
- loom-compile
63-
- check-readme
64-
- test-hyper
65-
- x86_64-fortanix-unknown-sgx
66-
- check-redox
67-
- wasm32-unknown-unknown
68-
- wasm32-wasi
69-
- check-external-types
70-
- check-fuzzing
71-
- check-unstable-mt-counters
50+
# - miri
51+
# - asan
52+
# - cross-check
53+
# - cross-test-with-parking_lot
54+
# - cross-test-without-parking_lot
55+
# - no-atomic-u64-test
56+
# - no-atomic-u64-check
57+
# - features
58+
# - minrust
59+
# - minimal-versions
60+
# - fmt
61+
# - clippy
62+
# - docs
63+
# - loom-compile
64+
# - check-readme
65+
# - test-hyper
66+
# - x86_64-fortanix-unknown-sgx
67+
# - check-redox
68+
# - wasm32-unknown-unknown
69+
# - wasm32-wasi
70+
# - check-external-types
71+
# - check-fuzzing
72+
# - check-unstable-mt-counters
7273
steps:
7374
- run: exit 0
7475

@@ -212,6 +213,34 @@ jobs:
212213
- name: Check tests with all features enabled
213214
run: cargo check --workspace --all-features --tests
214215

216+
test-tracing-instrumentation:
217+
# These tests use the as-yet unpublished `tracing-mock` crate to test the
218+
# tracing instrumentation present in Tokio. As such they are placed in
219+
# their own test crate outside of the workspace.
220+
needs: basics
221+
name: test tokio instrumentation
222+
runs-on: ubuntu-latest
223+
steps:
224+
- uses: actions/checkout@v3
225+
- name: Install Rust ${{ env.rust_stable }}
226+
uses: dtolnay/rust-toolchain@stable
227+
with:
228+
toolchain: ${{ env.rust_stable }}
229+
- name: Install cargo-nextest
230+
uses: taiki-e/install-action@v2
231+
with:
232+
tool: cargo-nextest
233+
234+
- uses: Swatinem/rust-cache@v2
235+
236+
- name: test tracing-instrumentation
237+
run: |
238+
set -euxo pipefail
239+
cargo nextest run
240+
working-directory: tokio/tests/tracing-instrumentation
241+
env:
242+
RUSTFLAGS: --cfg tokio_unstable -Dwarnings
243+
215244
valgrind:
216245
name: valgrind
217246
needs: basics
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]
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)