Skip to content

Conversation

@jan-xyz
Copy link
Contributor

@jan-xyz jan-xyz commented Aug 25, 2025

Changes

This adds tracing support for the tower layer. It was addressed briefly with @cijothomas on the CNCF slack, but we didn't discuss any details of the implementation. I took the liberty for now to take 2 major design decisions:

  1. General vs. Specialized tower layer: I chose to pick a general layer that does metrics and tracing together with a no-op tracer in case someone doesn't want to do tracing with this layer. I assume that long term people/teams will fully switch to OpenTelemetry for Metrics and Tracing and instead of specifying two layers which each inspect the request and response, it makes more sense to do this in one layer.

  2. Backwards compatibility: I tried to leave the original types in place which have the "Metric" implementation in the name. This is maybe a more smooth migration? I am not sure how helpful that actually is, and maybe we should just break compatibility in case we want to go with a unified layer.

Note: It currently does not include context extraction.

As a follow up I would also like to provide a way to use this as a client layer, where the semantics change a bit.

Merge requirement checklist

  • CONTRIBUTING guidelines followed
  • Unit tests added/updated (if applicable)
  • Appropriate CHANGELOG.md files updated for non-trivial, user-facing changes
  • Changes in public API reviewed (if applicable)

@jan-xyz jan-xyz requested a review from a team as a code owner August 25, 2025 12:57
@codecov
Copy link

codecov bot commented Aug 25, 2025

Codecov Report

❌ Patch coverage is 83.06452% with 42 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.9%. Comparing base (5479846) to head (7cc2289).

Files with missing lines Patch % Lines
opentelemetry-instrumentation-tower/src/lib.rs 83.0% 42 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##            main    #431     +/-   ##
=======================================
+ Coverage   54.4%   54.9%   +0.4%     
=======================================
  Files         71      71             
  Lines      11892   12061    +169     
=======================================
+ Hits        6476    6624    +148     
- Misses      5416    5437     +21     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jan-xyz jan-xyz changed the title Add tower tracing (feat) Add tower tracing Aug 25, 2025
@jan-xyz jan-xyz changed the title (feat) Add tower tracing feat: Add tower tracing Aug 25, 2025
@jan-xyz jan-xyz requested a review from cijothomas August 29, 2025 07:19
@jan-xyz
Copy link
Contributor Author

jan-xyz commented Aug 29, 2025

while working on this, I started to wonder how the overall strategy for this crate could look like, and I am wondering if my PR is maybe not going far enough. For the future we have multiple use cases for a (collection of?) tower layer(s).

So far I see at least 4:

  • HTTP Server
  • HTTP Client
  • gRPC Server
  • gRPC Client

As it stands now, it provides HTTP server support, for that it might make sense to also rename the structs accordingly to HTTPServerLayer a.s.o. I won't push the other 3 concerns into this PR, but I at least would have the plan to add these in the next couple of days/weeks if it fits this project since I need this functionality for a project I am currently working on.

It might even be an idea to provide some form of auto-detecting abstraction on top which figures out if it's in a server/client context or gRPC/HTTP exchange. I am not sure how realistic that is though, as I haven't looked into the details yet.

label_superset.extend(custom_response_attributes.clone());

// Update span
let span = this.future_state.otel_context.span();
Copy link
Member

Choose a reason for hiding this comment

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

if we activate the OTel Context in the request, we should be able to retrieve it from Context::Current instead of having to store it ourselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's not possible, I believe, or I am not sure how to solve it. The guard is a raw pointer (*const()) which means it is !Send but we have to store it for the response future to not drop it and lose the guard and for that it must be Send.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I rewrote the response future to be able to attach the context to it, which solves this problem. Please have another look!

@cijothomas
Copy link
Member

@cijothomas anything I can do to move this PR forward?

Sincere apologies for delay in getting back to reviewing. I left some comments in the PR. Its mostly working - the key part I want to change are

  1. Avoid SDK crate dependency
  2. Extract context from incoming request headers and use that context, if any, to start the span.

@jan-xyz jan-xyz requested a review from cijothomas November 25, 2025 22:54
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.

2 participants