Skip to content

Design document for otelhttpconv package #6859

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

dmathieu
Copy link
Member

@dmathieu dmathieu commented Feb 28, 2025

This provides a design document for a new instrumentation, otelhttpconv that would serve as a meta instrumentation for all HTTP packages to more easily share their behavior.

@dmathieu dmathieu added the Skip Changelog Allow PR to succeed without requiring an addition to the CHANGELOG label Feb 28, 2025
Copy link

codecov bot commented Feb 28, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 75.6%. Comparing base (dbaba60) to head (cfd8b48).

Additional details and impacted files

Impacted file tree graph

@@          Coverage Diff          @@
##            main   #6859   +/-   ##
=====================================
  Coverage   75.6%   75.6%           
=====================================
  Files        207     207           
  Lines      19354   19354           
=====================================
+ Hits       14643   14646    +3     
+ Misses      4275    4273    -2     
+ Partials     436     435    -1     

see 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dmathieu dmathieu marked this pull request as ready for review March 4, 2025 13:15
@dmathieu dmathieu requested a review from a team as a code owner March 4, 2025 13:15
@dmathieu
Copy link
Member Author

dmathieu commented Mar 4, 2025

cc @akats7 @scorpionknifes as code owners of HTTP implementations

Copy link
Member

@XSAM XSAM left a comment

Choose a reason for hiding this comment

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

Could you add an example for a certain existing HTTP instrumentation to describe how otelhttpconv is actually being used in HTTP instrumentation? This could also give other authors more clues about how to leverage otelhttpconv to reduce code repetition.

@dmathieu
Copy link
Member Author

I've added a sample implementation of an http.Handler to show what it would look like for implementations.
I'm happy to provide a full implementation of otelhttpconv as well, to make this code work. But I'd rather do that when we're nearing consensus to avoid having to change things too many times.


// NewResponseWrapper wraps additional data into the http.ResponseWriter,
// such as duration, status code and quantity of bytes read.
rww := otelhttpconv.NewResponseWrapper(w)
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this coupled to otelhttpconv.NewHTTPConv?
Are we sure that it would work with other custom semantic conventions?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think this goes with your other comment. If we make the body and response wrapper structs and internalize their logic then, this will indeed change.

Copy link
Member Author

Choose a reason for hiding this comment

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

So, even with structs for the wrappers, I think this design makes sense.
Building a response wrapper from an HTTPConv would be strange, as then each implementations would need to know how to build a wrapper as well.

Copy link
Member

Choose a reason for hiding this comment

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

as then each implementations would need to know how to build a wrapper as well.

But wouldn't the wrapper functionalities by detriment by what httpconv.Record is supposed to do? I feel like those structures are coupled to each other. E.g. I guess that for some httpconv the reponse needs BytesWritten but for other it is unnecessary.


// Client provides an interface for HTTP client instrumentations to set the
// proper semantic convention attributes and metrics into their data.
type Client interface {
Copy link
Member

@pellared pellared Mar 17, 2025

Choose a reason for hiding this comment

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

I think it would be good to have some "Rationale" or/and "Rejected Proposals" explaining the pros and cons behind the decision making.

For instance, why cannot we simply have a function a struct more or less like

func RecordClient(r *http.Request, params RecordClientParameters)

type RecordClientParameters struct {
  Tracer trace.Tracer
  Meter metric.Meter
  Error error
  Response *http.Response
  Duration time.Time
}

Copy link
Member Author

Choose a reason for hiding this comment

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

I've added an Alternatives section.

Copy link
Member

@pellared pellared left a comment

Choose a reason for hiding this comment

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

It would be nice to have a working prototype as a separate draft PR.

@dmathieu
Copy link
Member Author

It would be nice to have a working prototype as a separate draft PR.

I intend to do that. But I'd rather have the spec stabilize first, to avoid rewriting it several times.

Comment on lines +153 to +154
These interfaces are kept relatively simple on purpose, so they can be used as
foundations if folks wish to extend them with their own actual implementations.
Copy link
Member

Choose a reason for hiding this comment

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

What would be a problem to use a struct? They can still be used as foundations. The users can always create their own interfaces if they need to support different implementation.

Copy link
Member Author

Choose a reason for hiding this comment

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

How would you do that?
If we provide the following API:

otelhttp.NewTransport(http.DefaultTransport, otelhttp.WithHTTPConv(myCustomImplementation{}))

And otelhttp.WithHTTPConv takes a struct, you can't extend it. It has to be our implementation.

Copy link
Member

Choose a reason for hiding this comment

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

otelhttp would define the interface as this is the package that accepts input and not otelhttpconv which provides an implementation.

otelhttp should not expose otelhttpconv types

Copy link
Member Author

Choose a reason for hiding this comment

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

Let's discuss this during today's SIG meeting. We have different views here.

While otelhttp would definitely use this package, the idea here is that other packages which currently use the generated semconv package would too.
Then, they need the types exposed.

Copy link
Member

@pellared pellared Mar 20, 2025

Choose a reason for hiding this comment

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

Let's discuss this during today's SIG meeting. We have different views here.

👍

the idea here is that other packages which currently use the generated semconv package would too.

Sure but these can be struct and not interface.

Comment on lines +156 to +158
Once stable, we will not be able to change those interfaces anymore (adding,
renaming or deleting methods), as that would break backwards compatibility with
implementations.
Copy link
Member

Choose a reason for hiding this comment

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

Then what is our plan if we would like to add a new functionality?

Copy link
Member Author

Choose a reason for hiding this comment

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

Same as for the interfaces in the SDK. We either introduce a new interface, or we release a v2.

Copy link
Member

Choose a reason for hiding this comment

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

With a struct we could simply add new fields/method.


### Implementations

We will provide one official implementation of the described interfaces.
Copy link
Member

Choose a reason for hiding this comment

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

What is the point of exposing an interface if we want to provide only one implementation?

Copy link
Member Author

Choose a reason for hiding this comment

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

So that folks can provide their own implementation.
Also, I do mention that we may provide additional implementations later on, for unstable conventions for example.

Copy link
Member

@pellared pellared Mar 18, 2025

Choose a reason for hiding this comment

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

The places where we want to allow passing custom implementations should define the interface (e.g. otelhttp). otelhttpconv does not accept any custom implementation.

Reference: https://go.dev/wiki/CodeReviewComments#interfaces

To be honest, I am not even sure if we need to support custom semantic conventions (we never did that).

tracer: otel.Tracer("http"),
propagators: otel.GetTextMapPropagator(),
meter: otel.Meter("http"),
httpconv: otelhttpconv.NewHTTPConv(otel.Tracer("httpconv"), otel.Meter("httpconv")),
Copy link
Member

Choose a reason for hiding this comment

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

NewHTTPConv is not defined in the design.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry, that seemed clear to me. It creates an instance of our official implementation of the interface.
Since the implementation itself isn't in the design, I didn't add this method.

### Compatibility

These interfaces are kept relatively simple on purpose, so they can be used as
foundations if folks wish to extend them with their own actual implementations.
Copy link
Member

@pellared pellared Mar 18, 2025

Choose a reason for hiding this comment

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

Do we really want to support custom semconv implementations?
I think it is an overkill (and footgun). Shouldn't we just focus on OTel SemConv?
People not happy with OTel SemConv can create their own instrumentation libraries.
I propose that otelhttpconv has "concrete" implementations (functions, structs).

If we want to ever provide customization of semconv, I would rather add it on the instrumentation library layer as this is the API that the user is interacting with. otelhttpconv should be used "internally" by instrumentation libraries.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think being able to support custom semantic conventions is just a side effect of the modularity. The real interesting thing here would be to be able to support unstable semantic conventions, with no breaking changes on the code that supports stable ones.

Copy link
Member

@pellared pellared Mar 20, 2025

Choose a reason for hiding this comment

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

I find it hard to evaluate without code and examples.
Unstable semantic conventions could be also controlled by env vars.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Skip Changelog Allow PR to succeed without requiring an addition to the CHANGELOG
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants