Skip to content

Commit b453786

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 b453786

File tree

4 files changed

+159
-0
lines changed

4 files changed

+159
-0
lines changed

.github/workflows/ci.yml

Lines changed: 27 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-tokio-tracing-instrumentation
4748
- valgrind
4849
- test-unstable
4950
- miri
@@ -212,6 +213,32 @@ jobs:
212213
- name: Check tests with all features enabled
213214
run: cargo check --workspace --all-features --tests
214215

216+
test-tokio-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 via separate tracing-instrumentation crate
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+
cd tokio/tests/tracing-instrumentation
240+
cargo nextest run
241+
215242
valgrind:
216243
name: valgrind
217244
needs: basics
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[build]
2+
rustflags = ["--cfg", "tokio_unstable"]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "tracing-instrumentation"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
10+
[dev-dependencies]
11+
futures = { version = "0.3.0", features = ["async-await"] }
12+
tokio = { version = "1.33.0", path = "../..", features = ["full", "tracing"] }
13+
tracing = { version = "0.1.40", git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" }
14+
# tracing-core = { version = "0.1.32", git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" }
15+
tracing-mock = { version = "0.1.0", git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" }
16+
17+
[patch.crates-io]
18+
tracing = { git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" }
19+
# tracing-core = { git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" }
20+
# tracing-subscriber = { git = "https://github.com/tokio-rs/tracing.git", tag = "tracing-0.1.40" }
21+
22+
23+
[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)