Skip to content

OpenTelemetry TraceContext does not propagate through reactive context properly in 3.1.6 / 3.2.0 #38593

Closed as not planned
@caspianb

Description

@caspianb

When using webflux in conjunction with open-telemetry with micrometer context propagation, it is expected that the trace context should be accessible throughout the controller. However, after updating to 3.1.6 (or 3.2.0) the traceId is lost within the controller at various spots.

What is even more odd, is simply adding a @RequestBody param to the controller "fixes" the issue in 3.1.6 / 3.2.0.

Run the attached demo application and using postman or similar, call the endpoints using header (or any valid traceparent syntax header):

  • traceparent = 00-11111111111111111111111111111111-2222222222222222-01

In 3.1.5, the traceId will always be available. In 3.1.6 the traceId will not be available in the below root endpoint -- but in the /body endpoint it will be available.

As far as I can tell (via downgrading micrometer, otel-bridge, netty, etc when using spring-boot 3.1.6/3.2.0) the issue does not seem to come from a lower level library.

demo.zip

@Slf4j
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        Hooks.enableAutomaticContextPropagation();
    }

    static String getTraceId(Tracer tracer) {
        return Optional.ofNullable(tracer.currentSpan())
                .map(Span::context)
                .map(TraceContext::traceId)
                .orElse(null);
    }

    @RestController
    @RequiredArgsConstructor
    static class DemoController {
        private final Tracer tracer;

        @GetMapping
        Mono<String> getRoot() {
            // These are null in 3.1.6+
            log.info("Current traceId={}", getTraceId(tracer));
            return Mono.error(() -> {
                log.info("error supplier traceId={}", getTraceId(tracer));
                return new RuntimeException("returning error");
            });
        }

        @GetMapping("body")
        Mono<String> getWithBody(@RequestBody(required=false) String body) {
            // These calls propagate fine
            log.info("Current traceId={}", getTraceId(tracer));
            return Mono.error(() -> {
                log.info("error supplier traceId={}", getTraceId(tracer));
                return new RuntimeException("returning error");
            });
        }
    }

    @RestControllerAdvice
    @RequiredArgsConstructor
    static class ErrorHandler {
        private final Tracer tracer;

        @ExceptionHandler(Exception.class)
        ResponseEntity<String> handleError(Exception ex) {
            log.info("Encountered error: traceId={}", getTraceId(tracer));
            return ResponseEntity.ok("Error: " + ex.getMessage());
        }
    }

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    for: external-projectFor an external project and not something we can fixstatus: duplicateA duplicate of another issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions