Kroxylicious >= 0.17.0 no longer tolerates SLF4j1 on the runtime classpath
Raising for informational purposes. I don't actually think there is a Kroxylicious defect.
At runtime, Kroxylicious 0.16.0 and less would tolerate SLF4j v1 on the classpath, rather than v2. I don't believe this was actually ever the intent. The project declared dependency was SLF4j v2 since before the v0.1.0 release (a69806d7c7d0afaff61aedadfefc4293b95be95b).
I became aware of this when I tested the 0.17.0 release with https://github.com/andreaTP/kroxylicious-wasm. It works with Kroxylicious 0.16.0 and earlier but failed (hanging ITs) with 0.17.0.
025-10-28 14:32:32 <multiThreadIoEventLoopGroup-5-1> DEBUG io.netty.channel.AbstractChannelHandlerContext:292 - An exception was thrown by a user handler's exceptionCaught() method while handling the following exception:
java.lang.NoSuchMethodError: 'org.slf4j.spi.LoggingEventBuilder org.slf4j.Logger.atDebug()'
at io.kroxylicious.proxy.internal.ProxyChannelStateMachine.onClientActive(ProxyChannelStateMachine.java:261)
at io.kroxylicious.proxy.internal.KafkaProxyFrontendHandler.channelActive(KafkaProxyFrontendHandler.java:178)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelActive(AbstractChannelHandlerContext.java:220)
at io.kroxylicious.proxy.internal.KafkaProxyInitializer$1.lambda$channelActive$0(KafkaProxyInitializer.java:115)
at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934)
at java.base/java.util.concurrent.CompletableFuture.uniHandleStage(CompletableFuture.java:950)
at java.base/java.util.concurrent.CompletableFuture.handle(CompletableFuture.java:2372)
at java.base/java.util.concurrent.CompletableFuture.handle(CompletableFuture.java:144)
at io.kroxylicious.proxy.internal.KafkaProxyInitializer$1.channelActive(KafkaProxyInitializer.java:108)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelActive(AbstractChannelHandlerContext.java:220)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelActive(DefaultChannelPipeline.java:1417)
at io.netty.channel.DefaultChannelPipeline.fireChannelActive(DefaultChannelPipeline.java:862)
at io.netty.channel.AbstractChannel$AbstractUnsafe$2.operationComplete(AbstractChannel.java:391)
at io.netty.channel.AbstractChannel$AbstractUnsafe$2.operationComplete(AbstractChannel.java:374)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:603)
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:570)
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:505)
at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:649)
at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:638)
It is the position of the kafka-client dependeny in its pom that cause the issue.
https://github.com/andreaTP/kroxylicious-wasm/blob/main/pom.xml#L53
kafka-client has a transitive dependency on SLF4jv1, and as it appears before the kroxylicious-integration-test-support (which transitively brings in kroxylicious-runtime and SLF4j v2), Maven is letting SLF4jv1 prevail.
This causes the kroxylicious-wasm ITs to fail. The solution is to re-order the dependencies.
kroxylicious-runtime correctly announces its dependency on the SLF4j v2, so I don't think there is actually a Kroxylicious defect here.
If it turns out we see users falling into this trap, maybe we add code to Kroxylicious to check the SLF4j v1 and fail with a clear error message.
So this is a runtime classpath issue?
So this is a runtime classpath issue?
Yes.
The trap is the fact that kafka-client has a transitive dependency on SLF4j v1. If the user adds this to their classpath above the kroxylicious deps, SLF4j v1 will take precedence. That's what the WASM project did (before I fixed it). It was a bit obscure to debug. The tests were seemingly hanging on the create topic future. It wasn't until I raised the logging level that the classpath issue become apparent.