skywalking: Webflux plugin throw ClassCastException when defining a filter

Please answer these questions before submitting your issue.

  • Why do you submit this issue?
  • Question or discussion
  • Bug
  • Requirement
  • Feature or performance improvement

Bug

  • Which version of SkyWalking, OS and JRE? apm-webflux-5.x-plugin-6.4.0-SNAPSHOT, centos7, jdk8

  • What happen? I define a filter:

@Component
public class MyFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return chain.filter(new MyServerWebExchangeDecorator(exchange));
    }

    public static class MyServerWebExchangeDecorator extends ServerWebExchangeDecorator {
        public MyServerWebExchangeDecorator(ServerWebExchange delegate) {
            super(delegate);
        }
    }

}

@RestController
public class HelloController {

    @GetMapping("/hello")
    public Mono<String> hello() {
        return Mono.just("Hello World");
    }

}

and the plugin will throw ClassCastException:

DEBUG 2019-09-02 09:42:53:591 reactor-http-nio-2 AbstractClassEnhancePluginDefine :  prepare to enhance class org.springframework.web.server.adapter.DefaultServerWebExchange by org.apache.skywalking.apm.plugin.spring.webflux.v5.define.DefaultServerWebExchangeInstrumentation.
DEBUG 2019-09-02 09:42:53:592 reactor-http-nio-2 AbstractClassEnhancePluginDefine :  enhance class org.springframework.web.server.adapter.DefaultServerWebExchange by org.apache.skywalking.apm.plugin.spring.webflux.v5.define.DefaultServerWebExchangeInstrumentation completely.
DEBUG 2019-09-02 09:42:53:592 reactor-http-nio-2 SkyWalkingAgent :  Finish the prepare stage for org.springframework.web.server.adapter.DefaultServerWebExchange.
DEBUG 2019-09-02 09:42:53:598 reactor-http-nio-2 SkyWalkingAgent :  On Transformation class org.springframework.web.server.adapter.DefaultServerWebExchange.
ERROR 2019-09-02 09:42:53:631 reactor-http-nio-2 InstMethodsInter :  class[class org.springframework.web.reactive.DispatcherHandler] before method[handle] intercept failure
java.lang.ClassCastException: com.example.MyFilter$MyServerWebExchangeDecorator cannot be cast to org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance
	at org.apache.skywalking.apm.plugin.spring.webflux.v5.DispatcherHandlerHandleMethodInterceptor.beforeMethod(DispatcherHandlerHandleMethodInterceptor.java:51)
	at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:82)
	at org.springframework.web.reactive.DispatcherHandler.handle(DispatcherHandler.java)
	at org.springframework.web.server.handler.DefaultWebFilterChain.lambda$filter$0(DefaultWebFilterChain.java:122)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44)
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44)
	at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61)
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44)
	at reactor.core.publisher.Mono.subscribe(Mono.java:3848)
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172)
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56)
	at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:70)
	at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61)
	at reactor.netty.http.server.HttpServerHandle.onStateChange(HttpServerHandle.java:64)
	at reactor.netty.tcp.TcpServerBind$ChildObserver.onStateChange(TcpServerBind.java:226)
	at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:442)
	at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:91)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
	at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:161)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:682)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:617)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:534)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:906)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at java.lang.Thread.run(Thread.java:748)

and can fix it by HierarchyMatch in DefaultServerWebExchangeInstrumentation:

public class DefaultServerWebExchangeInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {

    @Override
    protected ClassMatch enhanceClass() {
        return byHierarchyMatch(new String[] {"org.springframework.web.server.ServerWebExchange"});
    }
    ......
}

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 17 (10 by maintainers)

Most upvoted comments

Do you reconsider the AsyncSpan, because the plugin throw NullPointerException when I print logs in a scheduler.

@Component
public class MyFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return chain.filter(new MyServerWebExchangeDecorator(exchange));
    }

    public static class MyServerWebExchangeDecorator extends ServerWebExchangeDecorator {

        private MyServerHttpRequestDecorator requestDecorator;

        public MyServerWebExchangeDecorator(ServerWebExchange delegate) {
            super(delegate);
            requestDecorator = new MyServerHttpRequestDecorator(delegate.getRequest());
        }

        @Override
        public ServerHttpRequest getRequest() {
            return requestDecorator;
        }
    }

    public static class MyServerHttpRequestDecorator extends ServerHttpRequestDecorator {

        public MyServerHttpRequestDecorator(ServerHttpRequest delegate) {
            super(delegate);
        }

        @Override
        public Flux<DataBuffer> getBody() {
            // using a scheduler
            return super.getBody().publishOn(Schedulers.elastic()).map(dataBuffer -> printBody(dataBuffer));
        }

        private DataBuffer printBody(DataBuffer dataBuffer) {
            // print body
            return dataBuffer;
        }
    }

}

@RestController
public class HelloController {

    @PostMapping("/hello")
    public Mono<String> hello(@RequestBody String body) {
        // do something with body
        return Mono.just("Hello World");
    }

}

and the NullPointerException:

DEBUG 2019-09-02 14:23:24:315 reactor-http-nio-2 SkyWalkingAgent :  Finish the prepare stage for org.springframework.web.server.ServerWebExchangeDecorator. 
DEBUG 2019-09-02 14:23:24:320 reactor-http-nio-2 SkyWalkingAgent :  On Transformation class org.springframework.web.server.ServerWebExchangeDecorator. 
ERROR 2019-09-02 14:23:24:523 elastic-2 InstMethodsInter :  class[class org.springframework.web.reactive.DispatcherHandler] after method[handleResult] intercept failure 
java.lang.NullPointerException
	at org.apache.skywalking.apm.agent.core.context.ContextManager.stopSpan(ContextManager.java:184)
	at org.apache.skywalking.apm.agent.core.context.ContextManager.stopSpan(ContextManager.java:180)
	at org.apache.skywalking.apm.plugin.spring.webflux.v5.DispatcherHandlerHandleResultMethodInterceptor.afterMethod(DispatcherHandlerHandleResultMethodInterceptor.java:46)
	at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:105)
	at org.springframework.web.reactive.DispatcherHandler.handleResult(DispatcherHandler.java)
	at org.springframework.web.reactive.DispatcherHandler.lambda$handle$2(DispatcherHandler.java:152)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:118)
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
	at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:241)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73)
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:204)
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:204)
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
	at reactor.core.publisher.MonoIgnoreThen$ThenAcceptInner.onNext(MonoIgnoreThen.java:296)
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:144)
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
	at reactor.core.publisher.MonoZip$ZipCoordinator.signal(MonoZip.java:247)
	at reactor.core.publisher.MonoZip$ZipInner.onNext(MonoZip.java:329)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192)
	at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onNext(FluxDefaultIfEmpty.java:92)
	at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73)
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
	at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext(FluxContextStart.java:103)
	at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:287)
	at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:331)
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
	at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121)
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:144)
	at reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.doComplete(FluxPublishOn.java:462)
	at reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.checkTerminated(FluxPublishOn.java:501)
	at reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.runAsync(FluxPublishOn.java:390)
	at reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.run(FluxPublishOn.java:484)
	at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
	at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)