-
Notifications
You must be signed in to change notification settings - Fork 41.1k
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
Provide configuration for ignoring routes from being sampled #34400
Comments
There's a way, but it's not pretty: @Configuration(proxyBeanMethods = false)
class MyObservationConfig {
@Bean
ObservationPredicate predicate() {
return (s, context) -> {
if (context instanceof ServerRequestObservationContext serverRequestObservationContext) {
HttpServletRequest carrier = serverRequestObservationContext.getCarrier();
return !carrier.getServletPath().startsWith("/actuator");
}
return true;
};
}
} The @jonatan-ivanov Do you know any way? |
@mhalbritter unfortunately as I mentioned in the original issue that doesn't work. At least it hasn't in my experience. The first span will be able to get ignored that way but any subsequent observations will still be reported. Inside the predicate there doesn't seem to be a way to get the parent span so you can't recursively find out if a new observation is related to a request. For example with that predicate, we can still see a call with a WebClient or RestTemplate get reported to our trace backend, since they are not using the |
If you want to prevent a span from being reported, you can:
You can inject your own sampler but it is for a different use-case, I would go with the options above. Here's a working example (similar to Moritz's: #34400 (comment)) that filters out Observations for actuator on the server (and on the client side): I'm not sure I get the issue with subsequent spans: with actuator, how do you have any (custom healthcheck)? You can get the parent, there is a |
@jonatan-ivanov The problem with this solution is the predicate only acts on spans. I know there is a What you end up getting is a bunch of Spring Security traces that are disconnected (have no parent) which makes a mess when you're using a tool like tempo and trying to query for things. This also means that any custom observation you have in your Spring application still get reported but you can't see the context of why they ran (if they were initiated by a call from a path that was excluded). Yes we do register custom health checks, but this use case goes beyond just ignoring actuator. |
I'm not sure what you mean by "the predicate only acts on spans". The
Since the
Now we are talking! :) If you don't want to see the Spring Security spans at all, you can disable them. If you only want to see them when the Observation of the server request is not filtered out, then similarly you can disable them only if they don't have a parent. |
A sample definitely helps, thanks. Can you please share it with us? |
@mhalbritter I did, it has no other changes than the configuration class above. I also provided all the dependencies used. If that isn't enough and you're looking for more let me know.. |
I guess what @mhalbritter is asking is a project we can clone, import to the IDE and debug. What we see is a code snippet above not a sample project. I haven't tried to set-up a sample project for this but there is one thing that confuses me, in your snippet I see this: if (context.getParentObservation() != null) { // <----- THIS IS NEVER TRUE But then you say:
So is there a parent or not. If there is a parent, what is it? |
There is never a parent. |
So the security spans should have a parent. That was my assumption when I tried to provide you a workaround: if they always have a parent, the only scenario when they don't is when their parent is ignored so you can ignore them too so you can do something like: if (context..getName().startsWith("spring.security.") && context.getParentObservation() == null) {
return false; // assuming parent is also ignored
} If this assumption does not hold, we need to fix instrumentation in Spring Security. |
Your assumption does not hold. ALL Observations (ignored or not) do not have a parent set. The function signature of Instead I tried using a @Bean
SpanExportingPredicate spanExportingPredicate() {
return new SpanExportingPredicate() {
@Override
public boolean isExportable(FinishedSpan span) {
return span.getTags().get("http.url") == null || !span.getTags().get("http.url").startsWith("/actuator");
}
};
} If it did get called I expect it would have the same problem as the |
Sigh. Here's the sample: sb34400.zip. Instructions to run are in the readme. |
@mhalbritter Thank You!
I'm sorry I missed that the parent is set after the predicate is tested so the parent will be there but not at the time where you need it in the predicate, I opened an issue to improve this: micrometer-metrics/micrometer#3678 I think not being able to see what request the Spring Security Observations belong to is an issue, I created one for that too: spring-projects/spring-security#12854
I missed that I think I can give you a not so simple workaround: // This adds the http.url keyvalue to security observations from the root (mvc) observation
// You add an ignoreSpan=true keyValue instead if you want, or something that can signal to the SpanExportingPredicate what to ignore
@Bean
ObservationFilter urlObservationFilter() {
return context -> {
if (context.getName().startsWith("spring.security.")) {
Context root = getRoot(context);
if (root.getName().equals("http.server.requests")) {
context.addHighCardinalityKeyValue(root.getHighCardinalityKeyValue("http.url"));
}
}
return context;
};
}
private Observation.Context getRoot(Observation.Context context) {
if (context.getParentObservation() == null) {
return context;
}
else {
return getRoot((Context) context.getParentObservation().getContextView());
}
}
// This ignores actuator spans but its logic depends on the ObservationFilter above
// Auto-configuration for SpanExportingPredicate was added in 3.1.0-M1
// So either you use 3.1.x or you can add the same to your config : https://github.com/spring-projects/spring-boot/pull/34002
@Bean
SpanExportingPredicate actuatorSpanExportingPredicate() {
return span -> !span.getTags().get("http.url").startsWith("/actuator");
} This workaround will not be necessary once the Spring Security issue above is fixed. |
Fine with me, in particular I do not think having The micrometer issue you opened I think will solve this when it is completed. Thanks for your thorough look into this issue. |
That's why I commented that you can use whatever data you want (e.g.: |
Hi @jonatan-ivanov I've tried to apply your fix by adding the config from #34002 but turns out that the It seems to be precisely the only bean that doesn't have the annotation, is that expected or could be a miss? https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryAutoConfiguration.java#L127 |
@sibethencourt If you check where the This seems intentional to me, if you check how spanProcessors.orderedStream().forEach(builder::addSpanProcessor); So it supports multiple processors that are additional. |
Hi Jonatan, thanks for the reply. Yes I managed to create a second span processor with support for I think if I create a new |
Hi, I'm coming back to this because it's getting more complicated for me to filter all the child spans of a particular root trace. Is this by design? Am I doing anything wrong? it seems to complicated for what it should really is 🤔 |
Right now, you have 3 options for configuring if a trace is reported.
Using the probability configuration properties, which only give you control over the percentage reported
Using a
ObservationRegistryPredicate
, however there doesn't seem to be a way to ignore any spans which are created as a result of a HTTP request because subsequent spans do not have an http.url attribute you can match on.Providing a custom
Sampler
. However theshouldSample
method does not receive the final attributes for the span and thus you cannot determine what path the sample is for.Ideally Spring would provide a way to configure this. The primary use case being to ignore any traces related to
/actuator
since these typically are only for health checks and clutter up the tracing backend.If there is another method I have not thought of that would work, I'd love to hear it!
The text was updated successfully, but these errors were encountered: