Skip to content

Commit 0f3328a

Browse files
authored
core: fix missing spans in serve tasks (#1243)
Currently, the `serve` function spawns tasks `instrument`ed with a `tracing` span for each accepted connection. This span is at the `DEBUG` level, so it's disabled with the default tracing configuration. This is fine, as the per-connection context is relatively verbose and is mainly useful for debugging. However, we also rely on this span for propagating the `INFO`-level spans which indicate which part of the proxy an event occurred in (inbound, outbound, etc). When the `DEBUG` span is enabled, it will be a child of these spans, so they are propagated to the spawned tasks. However, when the `DEBUG` span is _not_ enabled, nothing propagates the `INFO` spans. Since the default `tracing` configuration enables `INFO` but not `DEBUG`, we want those spans to be propagated to the tasks spawned in `serve`. This commit fixes the missing spans by moving the spawn inside of the `Span::in_scope` call, and using `in_current_span` rather than `instrument`. Now, if the per-connection `DEBUG` span is enabled, it will be the current span...but if it isn't, the `INFO` span will still be current, so the task will still have the `INFO` span as part of its span context regardless. Alternatively, we could have fixed this by changing the `instrument()` call to: ```rust .instrument(span) .in_current_span() ``` so that the task is always spawned in both the `DEBUG` span _and_ the current span. However, this is a bit less efficient, as it wraps the tasks in both spans even when the `INFO` span is not needed, so every time the task is polled, we would enter both spans.
1 parent 191f733 commit 0f3328a

File tree

1 file changed

+29
-29
lines changed

1 file changed

+29
-29
lines changed

linkerd/app/core/src/serve.rs

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ use linkerd_error::Error;
88
use tower::util::ServiceExt;
99
use tracing::{debug, debug_span, info, instrument::Instrument, warn};
1010

11-
/// Spawns a task that binds an `L`-typed listener with an `A`-typed
12-
/// connection-accepting service.
11+
/// Spawns a task that binds an `L`-typed listener with an `A`-typed connection-accepting service.
1312
///
1413
/// The task is driven until shutdown is signaled.
1514
pub async fn serve<M, S, I, A>(
@@ -40,38 +39,39 @@ pub async fn serve<M, S, I, A>(
4039
};
4140

4241
// The local addr should be instrumented from the listener's context.
43-
let span = debug_span!("accept", client.addr = %addrs.param());
42+
debug_span!("accept", client.addr = %addrs.param()).in_scope(|| {
43+
let accept = new_accept.new_service(addrs);
4444

45-
let accept = span.in_scope(|| new_accept.new_service(addrs));
46-
47-
// Dispatch all of the work for a given connection onto a connection-specific task.
48-
tokio::spawn(
49-
async move {
50-
match accept.ready_oneshot().err_into::<Error>().await {
51-
Ok(mut accept) => {
52-
match accept
53-
.call(io::ScopedIo::server(io))
54-
.err_into::<Error>()
55-
.await
56-
{
57-
Ok(()) => debug!("Connection closed"),
58-
Err(reason) if is_io(&*reason) => {
59-
debug!(%reason, "Connection closed")
45+
// Dispatch all of the work for a given connection onto a
46+
// connection-specific task.
47+
tokio::spawn(
48+
async move {
49+
match accept.ready_oneshot().err_into::<Error>().await {
50+
Ok(mut accept) => {
51+
match accept
52+
.call(io::ScopedIo::server(io))
53+
.err_into::<Error>()
54+
.await
55+
{
56+
Ok(()) => debug!("Connection closed"),
57+
Err(reason) if is_io(&*reason) => {
58+
debug!(%reason, "Connection closed")
59+
}
60+
Err(error) => info!(%error, "Connection closed"),
6061
}
61-
Err(error) => info!(%error, "Connection closed"),
62+
// Hold the service until the connection is complete. This
63+
// helps tie any inner cache lifetimes to the services they
64+
// return.
65+
drop(accept);
66+
}
67+
Err(error) => {
68+
warn!(%error, "Server failed to become ready");
6269
}
63-
// Hold the service until the connection is
64-
// complete. This helps tie any inner cache
65-
// lifetimes to the services they return.
66-
drop(accept);
67-
}
68-
Err(error) => {
69-
warn!(%error, "Server failed to become ready");
7070
}
7171
}
72-
}
73-
.instrument(span),
74-
);
72+
.in_current_span(),
73+
);
74+
});
7575
}
7676
}
7777
}

0 commit comments

Comments
 (0)