Skip to content

feat(rt): add TracingExecutor and rt-tracing-exec-force feature - #322

Open
seanmonstar wants to merge 1 commit into
masterfrom
sean/yopytotwomtu
Open

seanmonstar wants to merge 1 commit into
masterfrom
sean/yopytotwomtu

Conversation

@seanmonstar

Copy link
Copy Markdown
Member

I've been giving some thought to the long-running span. I can sympathize that it causes problems for many people, and there's basically no way to stop it. I'm leaning towards adding the automatic in_current_span was a mistake, at least in that it had unintended consequences. What made fixing this slow is that both behaviors are desired, and changing it could be considered breaking.

But, so be it. This is a soft behavioral breaking change. But, because the alternative is that people basically cannot fix it. Here's what it does.

  • Enabling the tracing feature no longer automatically makes the TokioExecutor spawn the future with in_current_span.
  • This introduces a new rt::TracingExecutor that can wrap any other executor to add that functionality in easily, if so desired.
  • And a (temporary?) crate feature is added, rt-tracing-exec-force, which will add back in the previous behavior, in case there's a library creating a client that you cannot otherwise customize, but you badly want the spans connected.

This seems like the least bad outcome. But curious what others think. @cratelyn @dswij? anyone else?

Closes hyperium/hyper#3904

@cratelyn cratelyn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for opening this, and for your time thinking through a solution to this situation! i strongly support removing the calls to Instrument::in_current_span() from <TokioExecutor as Executor>::execute().

the temporary opt-in rt-tracing-exec-force feature flag appears to be a reasonable stopgap to allow transitive dependents of hyper-util, i.e. users of libraries like kube-rs or the AWS SDK that might create a hyper client internally on behalf of a caller, to continue to opt-in to the existing behavior after a hyper-util release including this change. i support this as well.

most substantively, i have a question below about how we might go about supporting the alternate span propagation behaviors that different groups of users want. #323 is a draft based upon this branch that explores that space a bit.

This is a soft behavioral breaking change.

one meta question i have is whether this change should warrant a v0.2.0 release. i would lean towards the latter, to be explicit that this could potentially cause breakage for some users, myself. what do you think?

Comment thread src/rt/tracing.rs
Comment on lines +4 to +25
/// An executor that propagates the current tracing span to its futures.
///
/// The span is captured when [`execute`](Executor::execute) is called, and is
/// entered each time the future is polled or dropped. Execution is delegated to
/// the wrapped executor, without requiring a particular runtime.
///
/// Requires the `tracing` feature.
///
/// # Example
///
/// ```
/// # #[cfg(feature = "tokio")]
/// # {
/// use hyper_util::rt::{TokioExecutor, TracingExecutor};
///
/// let executor = TracingExecutor::new(TokioExecutor::new());
/// # }
/// ```
#[derive(Clone, Copy, Debug, Default)]
pub struct TracingExecutor<E> {
inner: E,
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been giving some thought to the long-running span. I can sympathize that
it causes problems for many people, and there's basically no way to stop it.
I'm leaning towards adding the automatic in_current_span was a mistake, at
least in that it had unintended consequences. What made fixing this slow is
that both behaviors are desired, and changing it could be considered
breaking.

(emphasis added)

i also agree that adding the automatic in_current_span() calls to TokioExecutor was a mistake. as you point out, both behaviors are desired by different users. my understanding is that this stems from different lifecycle semantics of various tracing_core::subscriber::Subscriber implementations.

users exporting traces via OpenTelemetry for example, must contend with the fact that only finished spans are sent to the collector. thus, users that wrap their subscriber in a tracing_opentelemetry::OpenTelemetryLayer layer will accordingly need to organize the tracing spans in their application code differently from users of subscribers like tracing_subscriber::fmt::Subscriber printing to stdout.

conversely, not all tracing subscribers have a way to visualize causal relationships between spans. whether an executor should spawn futures in a separate span that follows_from() the current span or within the current span depends on how and where events are being formatted.

to help account for both of these groups, i would propose that we expose more than one "tracing" executor from the perspective of hyper-util. i've opened #323 as a draft against this branch, exploring what that could look like.

for now i've only added a WithSpanExecutor<E> to instrument executed futures with a provided span, but i can imagine a FollowsFromExecutor<E> to build closely upon that. i am curious what you think of this direction!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, I did wonder if I should even include an additional executor wrapper, or leave that for a separate thing. I don't have to merge it at the same time, if it's less clear what a good set to provide is. I don't feel strongly, I don't have a need for these types myself, but figured I'd include it as an example and possibly useful thing. wdyt?

@dswij

dswij commented Sep 19, 2026

Copy link
Copy Markdown
Member

Agree. In retrospect, the addition of in_current_span caused a lot of issues.

There's #311 too, but I'm not convinced with the changes there. It's adding more creep when the issue is in TokioExecutor rather than trait.

cratelyn added a commit that referenced this pull request Sep 20, 2026
see #322 for more
information.

this commit introduces an additional `Executor` implementation to
accompany the `CurrentSpanExecutor` that executes spawned futures within
the current span at time of execution.

this would provide an alternative for users that wish to provide tracing
information, but do not want to run background futures in the current
span, which can interfere with some observability systems.

Signed-off-by: katelyn martin <git@katelyn.world>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Legacy Client pooling messes tower::TraceLayer tracing

3 participants