From 0b80f3d424de20887ed709d89dfdfa445a03c0c1 Mon Sep 17 00:00:00 2001
From: peachisai <96932958+peachisai@users.noreply.github.com>
Date: Sun, 29 Oct 2023 16:18:25 +0800
Subject: [PATCH] Add a netty-4.1.x plugin to trace http (#625)
---
.github/workflows/plugins-test.1.yaml | 1 +
CHANGES.md | 1 +
.../trace/component/ComponentsDefine.java | 2 +
apm-sniffer/config/agent.config | 6 +
.../netty-http-4.1.x-plugin/pom.xml | 46 ++++++
.../AddHttpRequestDecoderInterceptor.java | 64 +++++++++
.../AddHttpRequestEncoderInterceptor.java | 64 +++++++++
.../AddHttpResponseDecoderInterceptor.java | 64 +++++++++
.../AddHttpResponseEncoderInterceptor.java | 64 +++++++++
.../ChannelHandlerContextInterceptor.java | 52 +++++++
.../ChannelPipelineRemoveLastInterceptor.java | 50 +++++++
.../netty/http/RemoveHandlerInterceptor.java | 71 ++++++++++
.../netty/http/common/AttributeKeys.java | 55 +++++++
.../netty/http/common/NettyConstants.java | 33 +++++
.../http/config/NettyHttpPluginConfig.java | 50 +++++++
.../define/AbstractNettyInstrumentation.java | 35 +++++
.../ChannelHandlerContextInstrumentation.java | 64 +++++++++
.../define/ChannelHandlerInstrumentation.java | 63 ++++++++
.../ChannelPipelineInstrumentation.java | 63 ++++++++
.../HttpRequestDecoderInstrumentation.java | 65 +++++++++
.../HttpRequestEncoderInstrumentation.java | 65 +++++++++
.../HttpResponseDecoderInstrumentation.java | 65 +++++++++
.../HttpResponseEncoderInstrumentation.java | 65 +++++++++
...NettyHttpRequestDecoderTracingHandler.java | 133 +++++++++++++++++
...NettyHttpRequestEncoderTracingHandler.java | 134 ++++++++++++++++++
...ettyHttpResponseDecoderTracingHandler.java | 103 ++++++++++++++
...ettyHttpResponseEncoderTracingHandler.java | 82 +++++++++++
.../http/utils/HttpDataCollectUtils.java | 80 +++++++++++
.../plugin/netty/http/utils/TypeUtils.java | 68 +++++++++
.../src/main/resources/skywalking-plugin.def | 23 +++
apm-sniffer/optional-plugins/pom.xml | 1 +
.../java-agent/Optional-plugins.md | 3 +-
.../service-agent/java-agent/Plugin-list.md | 1 +
.../java-agent/Supported-list.md | 1 +
.../java-agent/configurations.md | 6 +-
.../netty-http-4.1.x-scenario/bin/startup.sh | 21 +++
.../config/expectedData.yaml | 81 +++++++++++
.../configuration.yml | 22 +++
.../netty-http-4.1.x-scenario/pom.xml | 101 +++++++++++++
.../src/main/assembly/assembly.xml | 41 ++++++
.../apm/testcase/netty/http/Application.java | 30 ++++
.../netty/http/controller/CaseController.java | 49 +++++++
.../netty/http/core/ClientService.java | 87 ++++++++++++
.../netty/http/core/ServerService.java | 62 ++++++++
.../netty/http/handler/UserClientHandler.java | 45 ++++++
.../netty/http/handler/UserServerHandler.java | 57 ++++++++
.../src/main/resources/application.yaml | 22 +++
.../support-version.list | 27 ++++
48 files changed, 2386 insertions(+), 2 deletions(-)
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/pom.xml
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpRequestDecoderInterceptor.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpRequestEncoderInterceptor.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpResponseDecoderInterceptor.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpResponseEncoderInterceptor.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/ChannelHandlerContextInterceptor.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/ChannelPipelineRemoveLastInterceptor.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/RemoveHandlerInterceptor.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/common/AttributeKeys.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/common/NettyConstants.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/config/NettyHttpPluginConfig.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/define/AbstractNettyInstrumentation.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/define/ChannelHandlerContextInstrumentation.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/define/ChannelHandlerInstrumentation.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/define/ChannelPipelineInstrumentation.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/define/HttpRequestDecoderInstrumentation.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/define/HttpRequestEncoderInstrumentation.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/define/HttpResponseDecoderInstrumentation.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/define/HttpResponseEncoderInstrumentation.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/handler/NettyHttpRequestDecoderTracingHandler.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/handler/NettyHttpRequestEncoderTracingHandler.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/handler/NettyHttpResponseDecoderTracingHandler.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/handler/NettyHttpResponseEncoderTracingHandler.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/utils/HttpDataCollectUtils.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/utils/TypeUtils.java
create mode 100644 apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/resources/skywalking-plugin.def
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/bin/startup.sh
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/config/expectedData.yaml
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/configuration.yml
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/pom.xml
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/src/main/assembly/assembly.xml
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/netty/http/Application.java
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/netty/http/controller/CaseController.java
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/netty/http/core/ClientService.java
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/netty/http/core/ServerService.java
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/netty/http/handler/UserClientHandler.java
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/netty/http/handler/UserServerHandler.java
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/src/main/resources/application.yaml
create mode 100644 test/plugin/scenarios/netty-http-4.1.x-scenario/support-version.list
diff --git a/.github/workflows/plugins-test.1.yaml b/.github/workflows/plugins-test.1.yaml
index dfa98f3dc..e271ad915 100644
--- a/.github/workflows/plugins-test.1.yaml
+++ b/.github/workflows/plugins-test.1.yaml
@@ -80,6 +80,7 @@ jobs:
- mssql-jdbc-scenario
- mybatis-3.x-scenario
- resteasy-4.x-scenario
+ - netty-http-4.1.x-scenario
steps:
- uses: actions/checkout@v2
with:
diff --git a/CHANGES.md b/CHANGES.md
index 96a55eaaa..46c54f8a3 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -17,6 +17,7 @@ Release Notes.
* Fix config length limitation.
* Support collecting ZGC memory pool metrics. Require OAP 9.7.0 to support these new metrics.
* Upgrade netty-codec-http2 to 4.1.100.Final
+* Add a netty-http 4.1.x plugin to trace HTTP requests.
#### Documentation
diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
index fff71474d..2334cb58e 100755
--- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -242,4 +242,6 @@ public class ComponentsDefine {
public static final OfficialComponent AEROSPIKE = new OfficialComponent(149, "Aerospike");
public static final OfficialComponent NACOS = new OfficialComponent(150, "Nacos");
+
+ public static final OfficialComponent NETTY_HTTP = new OfficialComponent(151, "Netty-http");
}
diff --git a/apm-sniffer/config/agent.config b/apm-sniffer/config/agent.config
index 1874a77be..6827c0a91 100755
--- a/apm-sniffer/config/agent.config
+++ b/apm-sniffer/config/agent.config
@@ -310,3 +310,9 @@ plugin.redisson.redis_parameter_max_length=${SW_PLUGIN_REDISSON_REDIS_PARAMETER_
plugin.redisson.operation_mapping_write=${SW_PLUGIN_REDISSON_OPERATION_MAPPING_WRITE:getset,set,setbit,setex,setnx,setrange,strlen,mset,msetnx,psetex,incr,incrby,incrbyfloat,decr,decrby,append,hmset,hset,hsetnx,hincrby,hincrbyfloat,hdel,rpoplpush,rpush,rpushx,lpush,lpushx,lrem,ltrim,lset,brpoplpush,linsert,sadd,sdiff,sdiffstore,sinterstore,sismember,srem,sunion,sunionstore,sinter,zadd,zincrby,zinterstore,zrange,zrangebylex,zrangebyscore,zrank,zrem,zremrangebylex,zremrangebyrank,zremrangebyscore,zrevrange,zrevrangebyscore,zrevrank,zunionstore,xadd,xdel,del,xtrim}
# Specify which command should be converted to read operation
plugin.redisson.operation_mapping_read=${SW_PLUGIN_REDISSON_OPERATION_MAPPING_READ:getrange,getbit,mget,hvals,hkeys,hlen,hexists,hget,hgetall,hmget,blpop,brpop,lindex,llen,lpop,lrange,rpop,scard,srandmember,spop,sscan,smove,zlexcount,zscore,zscan,zcard,zcount,xget,get,xread,xlen,xrange,xrevrange}
+# This config item controls that whether the Netty-http plugin should collect the http body of the request.
+plugin.nettyhttp.collect_request_body=${SW_PLUGIN_NETTYHTTP_COLLECT_REQUEST_BODY:false}
+# When `HTTP_COLLECT_REQUEST_BODY` is enabled, how many characters to keep and send to the OAP backend, use negative values to keep and send the complete body.
+plugin.nettyhttp.filter_length_limit=${SW_PLUGIN_NETTYHTTP_FILTER_LENGTH_LIMIT:1024}
+# When `HTTP_COLLECT_REQUEST_BODY` is enabled and content-type start with HTTP_SUPPORTED_CONTENT_TYPES_PREFIX, collect the body of the request , multiple paths should be separated by `,`
+plugin.nettyhttp.supported_content_types_prefix=${SW_PLUGIN_NETTYHTTP_SUPPORTED_CONTENT_TYPES_PREFIX:application/json,text/}
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/pom.xml b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/pom.xml
new file mode 100644
index 000000000..6e9b24ff7
--- /dev/null
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/pom.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+ org.apache.skywalking
+ optional-plugins
+ 9.1.0-SNAPSHOT
+
+ 4.0.0
+
+ apm-netty-http-4.1.x-plugin
+ netty-http-4.1.x-plugin
+
+
+ UTF-8
+ 4.1.51.Final
+
+
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+ provided
+
+
+
+
+
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpRequestDecoderInterceptor.java b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpRequestDecoderInterceptor.java
new file mode 100644
index 000000000..3b65f3f8d
--- /dev/null
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpRequestDecoderInterceptor.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.netty.http;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
+import org.apache.skywalking.apm.plugin.netty.http.handler.NettyHttpRequestDecoderTracingHandler;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+public class AddHttpRequestDecoderInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ ChannelHandlerContext ctx = (ChannelHandlerContext) allArguments[0];
+ ChannelPipeline pipeline = ctx.channel().pipeline();
+
+ if (pipeline.context(ctx.name()) == null) {
+ return ret;
+ }
+
+ String name = NettyHttpRequestDecoderTracingHandler.class.getName();
+ if (null != pipeline.context(name)) {
+ pipeline.remove(name);
+ }
+ pipeline.addAfter(ctx.name(), name, NettyHttpRequestDecoderTracingHandler.getInstance());
+
+ Map map = AttributeKeys.getOrCreateHandlerMap(ctx.channel());
+ map.put((ChannelHandler) objInst, NettyHttpRequestDecoderTracingHandler.getInstance());
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpRequestEncoderInterceptor.java b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpRequestEncoderInterceptor.java
new file mode 100644
index 000000000..ced4b0f9e
--- /dev/null
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpRequestEncoderInterceptor.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.netty.http;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
+import org.apache.skywalking.apm.plugin.netty.http.handler.NettyHttpRequestEncoderTracingHandler;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+public class AddHttpRequestEncoderInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ ChannelHandlerContext ctx = (ChannelHandlerContext) allArguments[0];
+ ChannelPipeline pipeline = ctx.channel().pipeline();
+
+ if (pipeline.context(ctx.name()) == null) {
+ return ret;
+ }
+
+ String name = NettyHttpRequestEncoderTracingHandler.class.getName();
+ if (null != pipeline.context(name)) {
+ pipeline.remove(name);
+ }
+ pipeline.addAfter(ctx.name(), name, NettyHttpRequestEncoderTracingHandler.getInstance());
+
+ Map map = AttributeKeys.getOrCreateHandlerMap(ctx.channel());
+ map.put((ChannelHandler) objInst, NettyHttpRequestEncoderTracingHandler.getInstance());
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpResponseDecoderInterceptor.java b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpResponseDecoderInterceptor.java
new file mode 100644
index 000000000..420e14514
--- /dev/null
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpResponseDecoderInterceptor.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.netty.http;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
+import org.apache.skywalking.apm.plugin.netty.http.handler.NettyHttpResponseDecoderTracingHandler;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+public class AddHttpResponseDecoderInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ ChannelHandlerContext ctx = (ChannelHandlerContext) allArguments[0];
+ ChannelPipeline pipeline = ctx.channel().pipeline();
+
+ if (pipeline.context(ctx.name()) == null) {
+ return ret;
+ }
+
+ String name = NettyHttpResponseDecoderTracingHandler.class.getName();
+ if (null != pipeline.context(name)) {
+ pipeline.remove(name);
+ }
+ pipeline.addAfter(ctx.name(), name, NettyHttpResponseDecoderTracingHandler.getInstance());
+
+ Map map = AttributeKeys.getOrCreateHandlerMap(ctx.channel());
+ map.put((ChannelHandler) objInst, NettyHttpResponseDecoderTracingHandler.getInstance());
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpResponseEncoderInterceptor.java b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpResponseEncoderInterceptor.java
new file mode 100644
index 000000000..4a965b1cb
--- /dev/null
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/AddHttpResponseEncoderInterceptor.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.netty.http;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
+import org.apache.skywalking.apm.plugin.netty.http.handler.NettyHttpResponseEncoderTracingHandler;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+public class AddHttpResponseEncoderInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ ChannelHandlerContext ctx = (ChannelHandlerContext) allArguments[0];
+ ChannelPipeline pipeline = ctx.channel().pipeline();
+
+ if (pipeline.context(ctx.name()) == null) {
+ return ret;
+ }
+
+ String name = NettyHttpResponseEncoderTracingHandler.class.getName();
+ if (null != pipeline.context(name)) {
+ pipeline.remove(name);
+ }
+ pipeline.addAfter(ctx.name(), name, NettyHttpResponseEncoderTracingHandler.getInstance());
+
+ Map map = AttributeKeys.getOrCreateHandlerMap(ctx.channel());
+ map.put((ChannelHandler) objInst, NettyHttpResponseEncoderTracingHandler.getInstance());
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/ChannelHandlerContextInterceptor.java b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/ChannelHandlerContextInterceptor.java
new file mode 100644
index 000000000..3dfb4f1aa
--- /dev/null
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/ChannelHandlerContextInterceptor.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.netty.http;
+
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
+
+import java.lang.reflect.Method;
+
+public class ChannelHandlerContextInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ if (ContextManager.isActive()) {
+ ContextSnapshot contextSnapshot = ContextManager.capture();
+ if (contextSnapshot != null) {
+ ((ChannelHandlerContext) objInst).channel().attr(AttributeKeys.CONTEXT_SNAPSHOT_ATTRIBUTE_KEY).set(contextSnapshot);
+ }
+ }
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/ChannelPipelineRemoveLastInterceptor.java b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/ChannelPipelineRemoveLastInterceptor.java
new file mode 100644
index 000000000..8e6346b8c
--- /dev/null
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/ChannelPipelineRemoveLastInterceptor.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.netty.http;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelPipeline;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.netty.http.common.NettyConstants;
+
+import java.lang.reflect.Method;
+
+public class ChannelPipelineRemoveLastInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ // If the removed handler is a SkyWalking enhanced handler, we continue removing the next which is the original handler before the instrumentation.
+ if (((ChannelHandler) ret).getClass().getName().startsWith(NettyConstants.HANDLER_PACKAGE_NAME)) {
+ return ((ChannelPipeline) objInst).removeLast();
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/RemoveHandlerInterceptor.java b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/RemoveHandlerInterceptor.java
new file mode 100644
index 000000000..0ae9ab6ca
--- /dev/null
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/RemoveHandlerInterceptor.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.netty.http;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+public class RemoveHandlerInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ ChannelHandlerContext ctx = (ChannelHandlerContext) allArguments[0];
+
+ Channel channel = ctx.channel();
+ ChannelPipeline pipeline = channel.pipeline();
+
+ // If the removal of the handler fails.
+ if (pipeline.context((ChannelHandler) objInst) != null) {
+ return ret;
+ }
+
+ Map map = channel.attr(AttributeKeys.HANDLER_CLASS_MAP).get();
+
+ if (map == null) {
+ return ret;
+ }
+
+ // If the removed handler has an enhanced handler associated with it, the associated handler should also be removed
+ ChannelHandler enhancedHandler = map.get(objInst);
+ if (enhancedHandler != null && pipeline.context(enhancedHandler) != null) {
+ pipeline.remove(enhancedHandler);
+ }
+
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+
+ }
+}
diff --git a/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/common/AttributeKeys.java b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/common/AttributeKeys.java
new file mode 100644
index 000000000..5734ab24e
--- /dev/null
+++ b/apm-sniffer/optional-plugins/netty-http-4.1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/netty/http/common/AttributeKeys.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.netty.http.common;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.util.AttributeKey;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class AttributeKeys {
+
+ public static final AttributeKey