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

Ability to exclude some endpoints from being traced #148

Closed
fatihdogmus opened this issue Jan 18, 2023 · 4 comments
Closed

Ability to exclude some endpoints from being traced #148

fatihdogmus opened this issue Jan 18, 2023 · 4 comments
Labels
question Further information is requested

Comments

@fatihdogmus
Copy link

Hello,

I've basically scoured the internet and the source codes, but couldn't find a way to exclude some URL patterns from being traced.

We use Otel bridge and zipkin exporter to get the trace data. Our use case is that there are a lot of traces regarding actuator, for both health and prometheus endpoints.

My question is that is there a way to exclude some URLs trace data being pushed to zipkin?

Thank you.

@marcingrzejszczak
Copy link
Contributor

Are you using Spring Boot? Then you should file an issue there to allow opting in for URLs or opting out of them.

In case you're not using Spring Boot you can create a SpanExportingPredicate that can filter out spans. Remember that you would have to filter out the whole graph of spans (like if a request comes in, a span is created, then a child one is created and then yet another one then you would need to filter them all out. Also you will have a problem when you're sending out a request within this trace to another application, then you will need to somehow filter that out too). SpanExportingPredicate can be used in Micrometer Tracing Brave bridge via CompositeSpanHandler and Micrometer Tracing Otel Bridge via CompositeSpanExporter .

@marcingrzejszczak marcingrzejszczak added the question Further information is requested label Jan 18, 2023
@fatihdogmus
Copy link
Author

fatihdogmus commented Jan 18, 2023

Yeah we are using spring boot. I will open an issue there. But meanwhile, I think I found a (hacky) workaround.

Since our sole use case is for the actuator endpoints, which don't send any HTTP requests, I created my own CompositeSpanExporter and overriden the export function like that:

public class FilteredZipkinExporter extends CompositeSpanExporter {

    public FilteredZipkinExporter(ZipkinSpanExporter zipkinSpanExporter) {
        super(List.of(zipkinSpanExporter), null, null, null);
    }

    @Override
    public CompletableResultCode export(Collection<SpanData> spans) {
        Set<String> actuatorTraceIds = spans.stream()
                .filter(span -> span.getName().contains("actuator"))
                .map(SpanData::getTraceId)
                .collect(toSet());

        List<SpanData> nonActuatorSpans = spans.stream()
                .filter(span -> !actuatorTraceIds.contains(span.getTraceId()))
                .collect(toList());

        return super.export(nonActuatorSpans);
    }
}

I take ZipkinSpanExporter that spring boot creates, so that I don't need to do any publishing myself. Then find the trace IDs of spans that have the name "actuator" in them, since Micro meter publishes the span name to include the actual URL, then I filter out all the spans that have this trace ID.

But this is not enough. Since ZipkinSpanExporter is also registered as bean, I need to replace the bean with a BeanPostProcessor otherwise two span exporter beans are present so both of them are called.

@Configuration
public class ZipkinSpanExporterPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof ZipkinSpanExporter zipkinSpanExporter) {
            return new FilteredZipkinExporter(zipkinSpanExporter);
        }
        return bean;
    }
}

Then only my FilteredZipkinExporter is present as a SpanExporter

I know this is hacky but I tried your solution, but that gets the spans one by one, so I can filter out the spans that are actually related to actuator, but all the other spans that are related with this trace gets pushed to zipkin.

But thanks to your pointers, I managed to hack a solution 🙂

@jonatan-ivanov
Copy link
Member

jonatan-ivanov commented Jan 18, 2023

Since you are using Boot, the instrumentation there is using the Observation API.
So by creating an ObservationPredicate @Bean you can exclude what you don't want. Here is an example with Spring MVC and Spring Cloud OpenFeign for incoming and outgoing HTTP requests for actuator endpoints, see: CommonActuatorConfig.java:

    @Bean
    public ObservationPredicate actuatorServerContextPredicate() {
        return (name, context) -> {
            if (name.equals("http.server.requests") && context instanceof ServerRequestObservationContext serverContext) {
                return !serverContext.getCarrier().getRequestURI().startsWith("/actuator");
            }
            else {
                return true;
            }
        };
    }

    @Bean
    public ObservationPredicate actuatorClientContextPredicate() {
        return (name, context) -> {
            if (name.equals("http.client.requests") && context instanceof FeignContext feignContext) {
                    return !feignContext.getCarrier().url().endsWith("/actuator/health");
            }
            else {
                return true;
            }
        };
    }

@jonatan-ivanov
Copy link
Member

As far as I can tell, the details here should answer your question, let me close the issue.
Please feel free to let us know if you want it to be reopened.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants