I am currently implementing Spring Cloud Sleuth in our project. I have a requirement to add the traceId to the response headers. Is there a way that this can be achieved?
Thanks,
Anoop
I am currently implementing Spring Cloud Sleuth in our project. I have a requirement to add the traceId to the response headers. Is there a way that this can be achieved?
Thanks,
Anoop
When using spring 5 and sleuth 2 , Please use the below sample.
https://github.com/robert07ravikumar/sleuth-sample
Steps : -
Create a webfilter with the below code and add the tracer id from the tracer object.
@Autowired
Tracer tracer;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("tracer-id", tracer.currentSpan().context().traceIdString());
chain.doFilter(request, response);
}
Add the annotation @ServletComponentScan
to the spring boot main class.
Using raj-kumar-bhakthavachalam example but using springframework.cloud.sleuth version 2.1.1 you may use as the following steps:
1. Autowired brave.Tracer
@Autowired
Tracer tracer
2. CurrentSpan returns TraceContext, get traceIdString
tracer.currentSpan().context().traceIdString()
If you're using jersey
One approach is to add jersey response filter
and use Trace (autowired) from spring sleuth
org.springframework.cloud.sleuth.Tracer
public class TraceHeaderInterceptor implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { val responseHeaders = responseContext.getHeaders(); if (!responseHeaders.containsKey(TRACE_ID_HEADER_NAME)) { val traceId = tracer.getCurrentSpan().context().traceIdString(); responseHeaders.add(TRACE_ID_HEADER_NAME, traceId); } } private static final String TRACE_ID_HEADER_NAME = "X-B3-Traceid"; private final Tracer tracer; public TraceHeaderInterceptor(Tracer tracer) { this.tracer = tracer; } }
We added this to our API gateway to avoid having to change each and every microservice
In Spring Sleuth 3.0.x, here is an example from the official doc.
@Component
@Order(TraceWebServletAutoConfiguration.TRACING_FILTER_ORDER + 1)
class MyFilter extends GenericFilterBean {
private final Tracer tracer;
MyFilter(Tracer tracer) {
this.tracer = tracer;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
Span currentSpan = this.tracer.currentSpan();
if (currentSpan == null) {
chain.doFilter(request, response);
return;
}
// for readability we're returning trace id in a hex form
((HttpServletResponse) response).addHeader("ZIPKIN-TRACE-ID",
currentSpan.context().traceIdString());
// we can also add some custom tags
currentSpan.tag("custom", "tag");
chain.doFilter(request, response);
}
}
There are 2 options. One is to provide your custom extractors - http://cloud.spring.io/spring-cloud-sleuth/1.0.x/#_customizations (it will be MUCH easier with version 1.2.0). Another option (much faster) is to create your own Filter that will be registered after TraceFilter was executed and before it's closed. You can there run
tracer.getCurrentSpan()
and add any info you need to the response.