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

URI_TEMPLATE_ATTRIBUTE used when available with feature flag. Fixes g… #1328

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

Conversation

JaroslawDembek
Copy link

@JaroslawDembek JaroslawDembek commented Jan 26, 2024

Fixes gh-1302.

@JaroslawDembek
Copy link
Author

@OlgaMaciaszek
I've added a feature flag.
TBH Now it doesn't look very neat now. getPath is very low as private method in utility class.
I do not think that somebody really needs old behaviour. Metrics are aggregated usually on path and IMO this is a memory leak rather than a feature.

@OlgaMaciaszek
Copy link
Collaborator

Thanks @JaroslawDembek, the idea would be to remove the old behaviour completely from the new release. I agree this is bug rather than a feature, and normally we would just change the behaviour, but I think when it comes to metric tags, it might be better to be very conservative with any changes, but I'm going to request @marcingrzejszczak to weigh in on this.

@OlgaMaciaszek
Copy link
Collaborator

@marcingrzejszczak FYI this is a continuation of this: #1327 (comment).

@OlgaMaciaszek
Copy link
Collaborator

Hi @JaroslawDembek, after some team chat, we think we can go forward with this fix without the flag after all, since there will bo no changes in the actual tag names; sorry for the confusion. Will you update the PR?

@JaroslawDembek JaroslawDembek marked this pull request as ready for review January 31, 2024 06:41
Copy link
Collaborator

@OlgaMaciaszek OlgaMaciaszek left a comment

Choose a reason for hiding this comment

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

@JaroslawDembek Thanks for updating the PR. I have noticed that the solution only seems to handle WebClient requests. Have added a comment, and another cosmetic one. Please take a look.

* @since 3.0.0
*/
final class LoadBalancerTags {

static final String UNKNOWN = "UNKNOWN";

static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Load-balanced requests can come from WebClient, but also RestClient and RestTemplate, so we need a way to handle all those scenarios.

Copy link
Author

Choose a reason for hiding this comment

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

RestClient is new to me and I almost forget about RestTemplate existence.
WebClient has two impls: MVC and WebFlux.
My change is for sure working in SpringBoot 3.1 + WebFlux.
I would start with writing test for all 4 scenarios. Could you advise me on pattern (code example of integration test setup e.g. some old or new PR) I should follow?

Copy link
Author

Choose a reason for hiding this comment

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

spring-projects/spring-framework#31882
There is a change in Spring about value of URI_TEMPLATE_ATTRIBUTE - now it will include baseUrl. Which for load balanced calls is http://{service-name}/...

Copy link
Collaborator

Choose a reason for hiding this comment

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

Since for a given client the baseUrl part of the template is going to remain the same anyhow, it should not be an issue when it comes to measuring the requests - the metrics will be effectively differentiated by the path. @marcingrzejszczak wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure what you mean by "WebClient has two implementations"? Spring supports blocking or MVC style communication, which is implemented by RestTemplate and RestClient, and reactive communication, implemented by WebClient.

We have integration tests that verify that LoadBalancerLifecycle calls are correctly executed. I'm thinking you could use a similar pattern to work on your integration test. Here are the test classes (they cover blocking load-balancing with and without retries and reactive load-balancing with and without retries):

  • BlockingLoadBalancerClientTests
  • RetryLoadBalancerInterceptorTests
  • ReactorLoadBalancerExchangeFilterFunctionTests
  • RetryableLoadBalancerExchangeFilterFunctionIntegrationTests
    Let me know if you need more help with this. If you do not have time and would like us to take over the PR to work on the non-reactive part, also no worries - let me know.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please update the license comment to Copyright 2012-2024 in all the files you've changed.

* @since 3.0.0
*/
final class LoadBalancerTags {

static final String UNKNOWN = "UNKNOWN";

static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since for a given client the baseUrl part of the template is going to remain the same anyhow, it should not be an issue when it comes to measuring the requests - the metrics will be effectively differentiated by the path. @marcingrzejszczak wdyt?

* @since 3.0.0
*/
final class LoadBalancerTags {

static final String UNKNOWN = "UNKNOWN";

static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate";
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure what you mean by "WebClient has two implementations"? Spring supports blocking or MVC style communication, which is implemented by RestTemplate and RestClient, and reactive communication, implemented by WebClient.

We have integration tests that verify that LoadBalancerLifecycle calls are correctly executed. I'm thinking you could use a similar pattern to work on your integration test. Here are the test classes (they cover blocking load-balancing with and without retries and reactive load-balancing with and without retries):

  • BlockingLoadBalancerClientTests
  • RetryLoadBalancerInterceptorTests
  • ReactorLoadBalancerExchangeFilterFunctionTests
  • RetryableLoadBalancerExchangeFilterFunctionIntegrationTests
    Let me know if you need more help with this. If you do not have time and would like us to take over the PR to work on the non-reactive part, also no worries - let me know.

@OlgaMaciaszek
Copy link
Collaborator

Hello @JaroslawDembek - have you seen my last comment? Are those tests what you were looking for? Do you need more help or just need some more time?

@JaroslawDembek
Copy link
Author

Hello @JaroslawDembek - have you seen my last comment? Are those tests what you were looking for? Do you need more help or just need some more time?

Hints were ok. It was a good starting point. I was able to work it out for reactive scenario, but unfortunatelly I hit a wall with RestClient + BlockingLoadbalancingClient - no easy access to uriTemplate field.
TBH I believe the old way should be abandoned and the whole thing should be moved to Observation API - low/high cardinality aspect is perfect for this.
Wdyt?
I've started this (looking as great learning oportunity), but definetely I need more time.

@OlgaMaciaszek
Copy link
Collaborator

OlgaMaciaszek commented Feb 20, 2024

Hi @JaroslawDembek - thanks a lot. Yes, it definitely makes sense to switch to Observation API - if you'd like to work on it, that sounds great. Also looking at the blocking implementation. In fact, since we're operating at the level of interceptor, we only get to work with org.springframework.http.HttpRequest, and specifically org.springframework.http.client.InterceptingClientHttpRequest, and we do not have access from the uriTemplate from there, as it doesn't pass it on.

Given that the issue that you've indicated may, in fact, cause considerable problems, I think, we should at least allow the users of the blocking implementation to avoid facing it by allowing a possibility to avoid tagging for path altogether. That, again, could be achieved by setting a flag. While, I agree it's not the most elegant solution, it may be better than not having a way to avoid the possible memory leak.

@OlgaMaciaszek OlgaMaciaszek self-assigned this Sep 27, 2024
@OlgaMaciaszek
Copy link
Collaborator

Hi @JaroslawDembek, I guess you do not have time to finish this up. I'd like to get this into our upcoming RC-1, so I'm going to cherry-pick your commits and add the remaining changes.

@OlgaMaciaszek
Copy link
Collaborator

I have also discussed using the Observation with @marcingrzejszczak and it seems that unless we want to create spans, it's better to stick with Meter and using URI templates, as a high cardinality tag will not really give us any additional insight.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WebClient's URI_TEMPLATE_ATTRIBUTE ignored by MicrometerStatsLoadBalancerLifecycle
3 participants