In Boot 3.0.3 you can add Hooks.enableAutomaticContextPropagation() to enable context propagation, resulting in trace IDs working in logs. Here is an issue to enable it by default https://github.com/spring-projects/spring-boot/issues/34201
However, this does not seem to work in a native image. This is reproducible by creating a minimal project and logging in a reactive context like a Kotlin suspend function. When the app is run in the JVM, there are trace IDs in logs; when built to a native image, the trace IDs are null. Checking in Zipkin, traces are produced. I cannot see any errors.
I've created a small reproducer. Here it is easy to see that running with bootRun and nativeRun results in different logs https://github.com/eduanb/trace-demo
Here is a little bit more context in the Micrometer slack . @chemicL already had a look from the Reactor side and believes the issue is Boot side.
Comment From: wilkinsona
@violetagg noticed that context propagation is not available during native compilation:
Field reactor.core.publisher.ContextPropagation#isContextPropagationAvailable set to false at build time
And that this is due to the following exception:
java.util.ServiceConfigurationError: io.micrometer.context.ContextAccessor: reactor.netty.contextpropagation.ChannelContextAccessor not a subtype
at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:593)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1244)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1273)
at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1309)
at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1393)
at java.base/java.lang.Iterable.forEach(Iterable.java:74)
at io.micrometer.context.ContextRegistry.loadContextAccessors(ContextRegistry.java:179)
at io.micrometer.context.ContextRegistry.<clinit>(ContextRegistry.java:40)
at reactor.core.publisher.ContextPropagation.<clinit>(ContextPropagation.java:69)
at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized0(Native Method)
at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1155)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(UnsafeFieldAccessorFactory.java:42)
at java.base/jdk.internal.reflect.ReflectionFactory.newFieldAccessor(ReflectionFactory.java:185)
at java.base/java.lang.reflect.Field.acquireFieldAccessor(Field.java:1132)
at java.base/java.lang.reflect.Field.getFieldAccessor(Field.java:1113)
at java.base/java.lang.reflect.Field.get(Field.java:425)
at org.springframework.aot.nativex.feature.PreComputeFieldFeature.provideFieldValue(PreComputeFieldFeature.java:85)
at org.springframework.aot.nativex.feature.PreComputeFieldFeature.iterateFields(PreComputeFieldFeature.java:64)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisElement$SubtypeReachableNotification.lambda$notifyCallback$0(AnalysisElement.java:129)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.AnalysisFuture.ensureDone(AnalysisFuture.java:63)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisElement.lambda$execute$2(AnalysisElement.java:170)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.executeCommand(CompletionExecutor.java:193)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.lambda$executeService$0(CompletionExecutor.java:177)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool.externalHelpQuiescePool(ForkJoinPool.java:2104)
at java.base/java.util.concurrent.ForkJoinPool.awaitQuiescence(ForkJoinPool.java:3321)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.complete(CompletionExecutor.java:243)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.PointsToAnalysis.doTypeflow(PointsToAnalysis.java:541)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.PointsToAnalysis.finish(PointsToAnalysis.java:529)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.AbstractAnalysisEngine.runAnalysis(AbstractAnalysisEngine.java:143)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:745)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:578)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:535)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:403)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:580)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:128)
This is happening at build time due to Spring Framework's PreComputeFieldFeature.
Comment From: violetagg
When reflection is used, Reactor Core handles some fields in a special way. Recently reflection was removed from reactor.core.publisher.ContextPropagation. I'm gonna provide a fix in Reactor Core.
Comment From: sdeleuze
Looks like this could be solved on Reactor side, so I close this issue for now.