Using Spring Cloud Sleuth version 3.1.4 and I want to insert the trace ID in the HTTP response headers. I created a bean of type GlobalFilter and trying to retrieve the trace ID string as follows
@Configuration
public class ResponseFilter {
@Autowired
Tracer tracer;
@Autowired
FilterUtils filterUtils;
final Logger logger =LoggerFactory.getLogger(ResponseFilter.class);
@Bean
public GlobalFilter postGlobalFilter() {
return (exchange, chain) -> {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
String traceId = tracer.currentSpan().context().traceIdString();
logger.debug("Adding the correlation id to the outbound headers. {}", traceId);
exchange.getResponse().getHeaders().add(FilterUtils.CORRELATION_ID, traceId);
logger.debug("Completing outgoing request for {}.", exchange.getRequest().getURI());
}));
};
}
}
I am getting tracer.currentSpan()
as NULL which is why it gives NPE for the above code.
CodePudding user response:
The problem is that the currentSpan will expire in the then() method and when you want to get it, it simply doesn't exist. Hence, you should take it sooner.
Here's a solution where you can get the current span and retrieve the traceId:
@Bean
public GlobalFilter postGlobalFilter() {
return (exchange, chain) -> {
final String traceId = Optional.ofNullable(tracer.currentSpan())
.map(Span::context)
.map(TraceContext::traceIdString)
.orElse("null");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
logger.debug("Adding the correlation id to the outbound headers. {}", traceId);
exchange.getResponse().getHeaders().add(FilterUtils.CORRELATION_ID, traceId);
logger.debug("Completing outgoing request for {}.",
exchange.getRequest().getURI());
}));
};
}
Note that I have used Java's Optional to deal with null values. You can use Mono.just(...).map(...).switchIfEmpty(...) as well.
Here's a cleaner way you could configure Spring Cloud Gateway's filter:
@Slf4j
@Configuration
@Profile({"dev","stage"})
@RequiredArgsConstructor
public class ResponseFilter implements GlobalFilter {
private final Tracer tracer;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
final String traceId = Optional.ofNullable(tracer.currentSpan())
.map(Span::context)
.map(TraceContext::traceIdString)
.orElse("null");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.debug("Adding the correlation id to the outbound headers. {}", traceId);
exchange.getResponse().getHeaders().add(FilterUtils.CORRELATION_ID, traceId);
log.debug("Completing outgoing request for {}.",
exchange.getRequest().getURI());
}));
}
}
Keep in mind that exposing traceId in the http response of the gateway is usually not a good idea (according to Spring Cloud Sleuth Documentation), unless you are in dev or stage and you want to use it for debugging purposes.