Context: springboot version: 3.0.0 and 3.1.1 I upgraded my projected to springboot 3 and use micrometer as traceability. In most flows, the traceId is attached in MDC. But at some exception handling scenarios, the traceId is missing. Also the same test scenario use at spirngboot2 + sleuth, the traceId remains.
my configs and code: (BTW i upload my test project with unit test at https://github.com/gecan123/tracing-test, you may click in my project and see all error scenarios in unit test. Also the test report is in github actions artifact, please read README.md)
**build.gradle**
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.1'
id 'io.spring.dependency-management' version '1.1.0'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'io.micrometer:micrometer-observation'
implementation 'io.micrometer:micrometer-tracing-bridge-brave'
implementation 'io.zipkin.reporter2:zipkin-reporter-brave'
testImplementation 'io.micrometer:micrometer-tracing-test'
testImplementation 'io.micrometer:micrometer-test'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-restassured'
}
**application.properties**
spring.application.name=spring-micrometer-tracing-demo
spring.jackson.serialization.indent_output = true
logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG
logging.pattern.level=%5p [${spring.zipkin.service.name:${spring.application.name:}},%X{traceId:-},%X{spanId:-}]
management.tracing.sampling.probability=1.0
@RestController
public class GlobalErrorController implements ErrorController {
private static Logger log = LoggerFactory.getLogger(GlobalErrorController.class);
@RequestMapping(value = "/error", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<ApiResponse> error(HttpServletRequest request) {
log.error("Exception occurred. apiError: {}", MDC.get("traceId"));
return status(500).body(new ApiResponse());
}
}
public class ApiResponse {
private String traceId;
public ApiResponse() {
this.traceId = MDC.get("traceId");
}
}
when i call /error endpoint directly, i get response with traceId.
when i call /path-not-exist and request will redirect to /error endpoint, but response without traceId.
Then i put more scenarios in my repo:
- If a endpoint throw exception and redirect to
/error, response without traceId. - If a endpoint only support POST, i call with get, redirect to
/error, response without traceId.
I have found the issue may raised by the class in spring is ServerHttpObservationFilter, but no idea why it run another time after exception is thrown.
Thank you and look forward to your reply!
Comment From: bclozel
This is a duplicate of #36285 and this limitation is explained in spring-projects/spring-framework#30675 and has been documented in spring-projects/spring-framework#29398.