Skip to content
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

Update HTTP metrics 'view' code to match the specification #4556

Merged
merged 9 commits into from
Nov 6, 2021

Conversation

jsuereth
Copy link
Contributor

@jsuereth jsuereth commented Nov 1, 2021

Sending this for preliminary review/thoughts. Important callouts:

  • There is a different set of rules for selecting identifying attributes for Client vs. Server.
  • This set of rules tries to give you a series of attributes to reconstruct a "URL", for the most part. See the tests in TemporaryMetricsView for an example of what this does.
  • The algorithm as it stands pays a runtime cost building the Set for the view every time it runs. Looking for ideas on how to optimise.

cc @trask

Things not done:

  • The semantic conventions strongly encourage using "abstract URL" paths, e.g. routing rules to annotate URL vs. a specific URL. We could do things like "find /[\d]+/" and erase it to "id" automagically, perhaps. But I suspect this cardinality isn't quite so bad as the peer-ip address cardinality is right now.

@jsuereth jsuereth requested a review from trask November 1, 2021 13:23
@jsuereth jsuereth marked this pull request as ready for review November 1, 2021 16:38
Copy link
Member

@trask trask left a comment

Choose a reason for hiding this comment

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

The algorithm as it stands pays a runtime cost building the Set for the view every time it runs. Looking for ideas on how to optimise.

We could create separate Sets for each "identity attribute" combination and then pass two Set<AttributeKey> params to applyView, e.g.

applyView(filtered, startAttributes, durationAlwaysInclude, identityInclude);
  • The semantic conventions strongly encourage using "abstract URL" paths, e.g. routing rules to annotate URL vs. a specific URL. We could do things like "find /[\d]+/" and erase it to "id" automagically, perhaps. But I suspect this cardinality isn't quite so bad as the peer-ip address cardinality is right now.

I'm not sure how to make this work as a default configuration for the Java agent. So many application have very high-cardinality paths (and even more have very high-cardinality query strings).

I would opt for not including http.url or http.target by default, but also ok if you want to use this to get feedback from users since metrics is still alpha.

http.route would be a good alternative. We have lots of instrumentation to capture the low-cardinality route. We use it to populate the http server span name, though we don't (yet) populate the actual http.route attribute. We'd need to do some additional work to capture http.route in a way that will get that attribute passed to endAttributes (instead of simply calling Span.setAttribute mid-span), but that's something we can probably figure out.

@jsuereth
Copy link
Contributor Author

jsuereth commented Nov 1, 2021

I would opt for not including http.url or http.target by default, but also ok if you want to use this to get feedback from users since metrics is still alpha.

We need something like it to identify the real metric-stream that has latency issues.

http.route would be a good alternative. We have lots of instrumentation to capture the low-cardinality route. We use it to populate the http server span name, though we don't (yet) populate the actual http.route attribute. We'd need to do some additional work to capture http.route in a way that will get that attribute passed to endAttributes (instead of simply calling Span.setAttribute mid-span), but that's something we can probably figure out.

This sounds like what http.target is meant to be in the metric semantic conventions. I'd be all about moving to this, is that realistic to do?

I would opt for not including http.url or http.target by default, but also ok if you want to use this to get feedback from users since metrics is still alpha.

I wonder how much of the issue was actually around net.peer.ip vs. the url itself. I'd like to get rid of the pure url for something more path-y, but I think this metric isn't very usable without the path right now.

@trask
Copy link
Member

trask commented Nov 1, 2021

This sounds like what http.target is meant to be in the metric semantic conventions. I'd be all about moving to this, is that realistic to do?

yes, I think so

I wonder how much of the issue was actually around net.peer.ip vs. the url itself. I'd like to get rid of the pure url for something more path-y, but I think this metric isn't very usable without the path right now.

Java web routing frameworks make it so easy to encode parameters into paths that it's really common.

Since metrics is alpha, we can merge as-is and open an issue to migrate to http.route. Let's give a day to see if feedback from anyone else.

@jsuereth
Copy link
Contributor Author

jsuereth commented Nov 1, 2021

Sounds good. Agreed that http.route is the right long-term solution. If it's there now, I'd be more than happy to cut this to:

http.scheme, http.host and http.route

if we consistently have them available in client + server.

@trask
Copy link
Member

trask commented Nov 1, 2021

Sounds good. Agreed that http.route is the right long-term solution. If it's there now, I'd be more than happy to cut this to:

http.scheme, http.host and http.route

if we consistently have them available in client + server.

ah, that's a good point, there's very few Java http client libraries that have a "route" concept, so while http.route will be good for server instrumentation, we'd have to do something different for client instrumentation

@mateuszrzeszutek
Copy link
Member

http.scheme, http.host and http.route

if we consistently have them available in client + server.

Unfortunately, none of our HTTP client instrumentations set these attributes; they're only set by the server isntrumentations (http.route is very rare though)

http.route would be a good alternative. We have lots of instrumentation to capture the low-cardinality route. We use it to populate the http server span name, though we don't (yet) populate the actual http.route attribute. We'd need to do some additional work to capture http.route in a way that will get that attribute passed to endAttributes (instead of simply calling Span.setAttribute mid-span), but that's something we can probably figure out.

I've been thinking of refactoring the ServerSpanNaming into a HttpRouteHolder (name's provisional 😄 ) that'll set both the span name and the http.route. I thought it could be added as a ContextCustomizer and retrieved from the context when needed to set the name/route. Passing this to the AttributesExtractor would probably require adding Context as an additional attribute, which would make end() accept 5 attributes -- which is quite a lot. Instead, since the RequestListener already gets the Context passed to its methods, maybe we could get the attribute from the context directly there?

@trask
Copy link
Member

trask commented Nov 3, 2021

I've been thinking of refactoring the ServerSpanNaming into a HttpRouteHolder (name's provisional 😄 ) that'll set both the span name and the http.route.

👍

Passing this to the AttributesExtractor would probably require adding Context as an additional attribute, which would make end() accept 5 attributes -- which is quite a lot. Instead, since the RequestListener already gets the Context passed to its methods, maybe we could get the attribute from the context directly there?

this is going to be a problem for metrics for any attributes that get set mid-span. I wish we could call span.getAttributes() on end and use that as the baseline for metrics attributes. @jsuereth @jkwatson any ideas?

@jkwatson
Copy link
Contributor

jkwatson commented Nov 3, 2021

this is going to be a problem for metrics for any attributes that get set mid-span. I wish we could call span.getAttributes() on end and use that as the baseline for metrics attributes. @jsuereth @jkwatson any ideas?

No ideas here. Unfortunately, since we can't expose this data on the API's Span, due to the streaming SDK requirement, we're pretty hamstrung. It would have to be something that the SDK itself would be able to provide. Probably some new feature of combined tracing/logs/metrics SDK that would enable this kind of thing.

I've also been pondering that some of this could probably be accomplished if there were a way for an API user to register a "Span callback" that got updates to the span also fed to it, but I don't know what that callback interface would have to look like (probably almost exactly like the span interface?)

@jsuereth
Copy link
Contributor Author

jsuereth commented Nov 3, 2021

I've also been pondering that some of this could probably be accomplished if there were a way for an API user to register a "Span callback" that got updates to the span also fed to it, but I don't know what that callback interface would have to look like (probably almost exactly like the span interface?)

Would it make sense to have a span-processor that generates metrics? Really wish we had that level of integration.

However, this is all kind of beside the point.

What's the next steps on this PR? I think we need to clean up what we have now, as we know it causes issues. I've kind of lost track in this discussion what changes I should try to make.

@trask
Copy link
Member

trask commented Nov 3, 2021

What's the next steps on this PR?

I'm not sure what's worse for the immediate 1.8.0 release 🤷‍♂️

  • cardinality explosion due to inclusion of http.url/http.target, or
  • useless metrics due to lack of http.url/http.target

I'm open to either. Let's chat and decide in tomorrow's SIG meeting(s).

@jsuereth
Copy link
Contributor Author

jsuereth commented Nov 4, 2021

Updated based on Java SiG discussions:

  • We only use http.url on the client. I created a really dumb query-param scrubber that's meant to help limit cardinality. I can make this more robust or use an existing utility (ideally) if we have one.
  • We use http.route on the server and fall back to http.target. This assumes we'll have cardinality limits in the SDK by the time this is released.

Copy link
Member

@trask trask left a comment

Choose a reason for hiding this comment

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

thx!

@trask trask merged commit d3f8ab6 into open-telemetry:main Nov 6, 2021
@jsuereth jsuereth deleted the wip-http-semconv branch November 8, 2021 13:45
RashmiRam pushed a commit to RashmiRam/opentelemetry-auto-instr-java that referenced this pull request May 23, 2022
…metry#4556)

* Update HTTP metrics 'view' code to match the specification, including optional attribute rules.

* Update server metrics test for new logic.

* Fix client metrics test.

* Spotless fix.

* Updates from Java SiG discussion.

* Fixes from review.

* Apply suggestions from code review

Co-authored-by: Trask Stalnaker <[email protected]>

* Update spotless from code reivew merge.

Co-authored-by: Trask Stalnaker <[email protected]>
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.

5 participants