Add a netty-4.1.x plugin to trace http (#625)

This commit is contained in:
peachisai 2023-10-29 16:18:25 +08:00 committed by GitHub
parent c94b409b28
commit 0b80f3d424
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 2386 additions and 2 deletions

View File

@ -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:

View File

@ -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

View File

@ -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");
}

View File

@ -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/}

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.apache.skywalking</groupId>
<artifactId>optional-plugins</artifactId>
<version>9.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-netty-http-4.1.x-plugin</artifactId>
<name>netty-http-4.1.x-plugin</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<netty.version>4.1.51.Final</netty.version>
</properties>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${netty.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -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<ChannelHandler, ChannelHandler> 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) {
}
}

View File

@ -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<ChannelHandler, ChannelHandler> 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) {
}
}

View File

@ -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<ChannelHandler, ChannelHandler> 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) {
}
}

View File

@ -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<ChannelHandler, ChannelHandler> 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) {
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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<ChannelHandler, ChannelHandler> 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) {
}
}

View File

@ -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<Map<ChannelHandler, ChannelHandler>> HANDLER_CLASS_MAP = AttributeKey.valueOf("skywalking_handler_class_map");
public static final AttributeKey<AbstractSpan> HTTP_CLIENT_SPAN = AttributeKey.valueOf("skywalking_http_client_span");
public static final AttributeKey<HttpHeaders> HTTP_REQUEST_HEADER = AttributeKey.valueOf("skywalking_http_request_header");
public static final AttributeKey<AbstractSpan> HTTP_SERVER_SPAN = AttributeKey.valueOf("skywalking_http_server_span");
public static final AttributeKey<ContextSnapshot> CONTEXT_SNAPSHOT_ATTRIBUTE_KEY = AttributeKey.valueOf("skywalking_context_snapshot");
private AttributeKeys() {
}
public static Map<ChannelHandler, ChannelHandler> getOrCreateHandlerMap(Channel channel) {
Map<ChannelHandler, ChannelHandler> map = channel.attr(HANDLER_CLASS_MAP).get();
if (map == null) {
map = new HashMap<>();
channel.attr(HANDLER_CLASS_MAP).set(map);
}
return map;
}
}

View File

@ -0,0 +1,33 @@
/*
* 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;
public class NettyConstants {
public static final String NETTY_HTTP_OPERATION_PREFIX = "Netty-http:";
public static final String HTTP_PROTOCOL_PREFIX = "http://";
public static final String HTTPS_PROTOCOL_PREFIX = "https://";
public static final String HANDLER_PACKAGE_NAME = "org.apache.skywalking.apm.plugin.netty.http.handler";
private NettyConstants() {
}
}

View File

@ -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.config;
import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
public class NettyHttpPluginConfig {
public static class Plugin {
@PluginConfig(root = NettyHttpPluginConfig.class)
public static class NettyHttp {
/**
* This config item controls that whether the Netty Http plugin should collect the http body of the request.
*/
public static boolean COLLECT_REQUEST_BODY = false;
/**
* If {@link Plugin.NettyHttp#COLLECT_REQUEST_BODY} is enabled,
* this limitation threshold controls the max size of collected HTTP body.
* Use the negative value to represent the unlimited threshold, which could cause OOM.
*/
public static int FILTER_LENGTH_LIMIT = 1024;
/**
* If {@link Plugin.NettyHttp#COLLECT_REQUEST_BODY} is enabled,
* this config scopes the types of HTTP content for collecting HTTP request body.
* Use a comma to separate multiple types.
*/
public static String SUPPORTED_CONTENT_TYPES_PREFIX = "application/json,text/";
}
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.define;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
public abstract class AbstractNettyInstrumentation extends ClassEnhancePluginDefine {
@Override
public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
return new StaticMethodsInterceptPoint[0];
}
@Override
protected String[] witnessClasses() {
return new String[]{"io.netty.handler.codec.compression.SnappyFrameEncoder"};
}
}

View File

@ -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.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class ChannelHandlerContextInstrumentation extends AbstractNettyInstrumentation {
@Override
protected ClassMatch enhanceClass() {
return byName("io.netty.channel.AbstractChannelHandlerContext");
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("write").and(takesArguments(3));
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.netty.http.ChannelHandlerContextInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class ChannelHandlerInstrumentation extends AbstractNettyInstrumentation {
@Override
protected ClassMatch enhanceClass() {
return MultiClassNameMatch.byMultiClassMatch("io.netty.handler.codec.ByteToMessageDecoder", "io.netty.handler.codec.MessageToByteEncoder");
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("handlerRemoved");
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.netty.http.RemoveHandlerInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class ChannelPipelineInstrumentation extends AbstractNettyInstrumentation {
@Override
protected ClassMatch enhanceClass() {
return HierarchyMatch.byHierarchyMatch("io.netty.channel.ChannelPipeline");
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("removeLast");
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.netty.http.ChannelPipelineRemoveLastInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class HttpRequestDecoderInstrumentation extends AbstractNettyInstrumentation {
@Override
protected ClassMatch enhanceClass() {
return LogicalMatchOperation.or(HierarchyMatch.byHierarchyMatch("io.netty.handler.codec.http.HttpRequestDecoder"), MultiClassNameMatch.byMultiClassMatch("io.netty.handler.codec.http.HttpRequestDecoder"));
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("handlerAdded");
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.netty.http.AddHttpRequestDecoderInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class HttpRequestEncoderInstrumentation extends AbstractNettyInstrumentation {
@Override
protected ClassMatch enhanceClass() {
return LogicalMatchOperation.or(HierarchyMatch.byHierarchyMatch("io.netty.handler.codec.http.HttpRequestEncoder"), MultiClassNameMatch.byMultiClassMatch("io.netty.handler.codec.http.HttpRequestEncoder"));
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("handlerAdded");
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.netty.http.AddHttpRequestEncoderInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class HttpResponseDecoderInstrumentation extends AbstractNettyInstrumentation {
@Override
protected ClassMatch enhanceClass() {
return LogicalMatchOperation.or(HierarchyMatch.byHierarchyMatch("io.netty.handler.codec.http.HttpResponseDecoder"), MultiClassNameMatch.byMultiClassMatch("io.netty.handler.codec.http.HttpResponseDecoder"));
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("handlerAdded");
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.netty.http.AddHttpResponseDecoderInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class HttpResponseEncoderInstrumentation extends AbstractNettyInstrumentation {
@Override
protected ClassMatch enhanceClass() {
return LogicalMatchOperation.or(HierarchyMatch.byHierarchyMatch("io.netty.handler.codec.http.HttpResponseEncoder"), MultiClassNameMatch.byMultiClassMatch("io.netty.handler.codec.http.HttpResponseEncoder"));
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("handlerAdded");
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.netty.http.AddHttpResponseEncoderInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,133 @@
/*
* 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.handler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslHandler;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
import org.apache.skywalking.apm.plugin.netty.http.common.NettyConstants;
import org.apache.skywalking.apm.plugin.netty.http.config.NettyHttpPluginConfig;
import org.apache.skywalking.apm.plugin.netty.http.utils.HttpDataCollectUtils;
import org.apache.skywalking.apm.plugin.netty.http.utils.TypeUtils;
import java.net.InetSocketAddress;
@ChannelHandler.Sharable
public class NettyHttpRequestDecoderTracingHandler extends ChannelInboundHandlerAdapter {
private static final ILog LOGGER = LogManager.getLogger(NettyHttpRequestDecoderTracingHandler.class);
private static class SingletonHolder {
private static final NettyHttpRequestDecoderTracingHandler INSTANCE = new NettyHttpRequestDecoderTracingHandler();
}
public static NettyHttpRequestDecoderTracingHandler getInstance() {
return NettyHttpRequestDecoderTracingHandler.SingletonHolder.INSTANCE;
}
private NettyHttpRequestDecoderTracingHandler() {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
if (TypeUtils.isFullHttpRequest(msg)) {
FullHttpRequest request = (FullHttpRequest) msg;
AbstractSpan span = createEntrySpan(ctx, request);
if (NettyHttpPluginConfig.Plugin.NettyHttp.COLLECT_REQUEST_BODY) {
HttpDataCollectUtils.collectHttpRequestBody(request.headers(), request.content(), span);
}
} else if (TypeUtils.isHttpRequest(msg)) {
// if headers before body arrive
createEntrySpan(ctx, (HttpRequest) msg);
ctx.channel().attr(AttributeKeys.HTTP_REQUEST_HEADER).set(((HttpRequest) msg).headers());
} else if (TypeUtils.isLastHttpContent(msg)) {
AbstractSpan span = ctx.channel().attr(AttributeKeys.HTTP_SERVER_SPAN).get();
HttpHeaders headers = ctx.channel().attr(AttributeKeys.HTTP_REQUEST_HEADER).getAndSet(null);
if (NettyHttpPluginConfig.Plugin.NettyHttp.COLLECT_REQUEST_BODY) {
HttpDataCollectUtils.collectHttpRequestBody(headers, ((LastHttpContent) msg).content(), span);
}
}
} catch (Exception e) {
LOGGER.error("Fail to trace netty http request", e);
} finally {
try {
ctx.fireChannelRead(msg);
} catch (Throwable throwable) {
AbstractSpan span = ctx.channel().attr(AttributeKeys.HTTP_SERVER_SPAN).getAndSet(null);
if (span != null) {
span.errorOccurred();
span.log(throwable);
Tags.HTTP_RESPONSE_STATUS_CODE.set(span, 500);
span.asyncFinish();
}
throw throwable;
}
}
}
private AbstractSpan createEntrySpan(ChannelHandlerContext ctx, HttpRequest request) {
AbstractSpan lastSpan = ctx.channel().attr(AttributeKeys.HTTP_SERVER_SPAN).getAndSet(null);
if (null != lastSpan) {
lastSpan.asyncFinish();
}
HttpHeaders headers = request.headers();
ContextCarrier contextCarrier = new ContextCarrier();
for (CarrierItem item = contextCarrier.items(); item.hasNext(); ) {
item = item.next();
item.setHeadValue(headers.get(item.getHeadKey()));
}
InetSocketAddress address = (InetSocketAddress) ctx.channel().localAddress();
String peer = address.getAddress().getHostAddress() + ":" + address.getPort();
String url = peer + request.uri();
String method = request.method().name();
AbstractSpan span = ContextManager.createEntrySpan(NettyConstants.NETTY_HTTP_OPERATION_PREFIX + request.uri(), contextCarrier);
span.prepareForAsync();
SpanLayer.asHttp(span);
span.setComponent(ComponentsDefine.NETTY_HTTP);
Tags.HTTP.METHOD.set(span, method);
boolean sslFlag = ctx.channel().pipeline().context(SslHandler.class) != null;
Tags.URL.set(span, sslFlag ? NettyConstants.HTTPS_PROTOCOL_PREFIX + url : NettyConstants.HTTP_PROTOCOL_PREFIX + url);
ctx.channel().attr(AttributeKeys.HTTP_SERVER_SPAN).set(span);
ContextManager.stopSpan(span);
return span;
}
}

View File

@ -0,0 +1,134 @@
/*
* 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.handler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.AsciiString;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
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.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
import org.apache.skywalking.apm.plugin.netty.http.common.NettyConstants;
import org.apache.skywalking.apm.plugin.netty.http.config.NettyHttpPluginConfig;
import org.apache.skywalking.apm.plugin.netty.http.utils.HttpDataCollectUtils;
import org.apache.skywalking.apm.plugin.netty.http.utils.TypeUtils;
import java.net.InetSocketAddress;
@ChannelHandler.Sharable
public class NettyHttpRequestEncoderTracingHandler extends ChannelOutboundHandlerAdapter {
private static class SingletonHolder {
private static final NettyHttpRequestEncoderTracingHandler INSTANCE = new NettyHttpRequestEncoderTracingHandler();
}
public static NettyHttpRequestEncoderTracingHandler getInstance() {
return SingletonHolder.INSTANCE;
}
private NettyHttpRequestEncoderTracingHandler() {
}
private static final ILog LOGGER = LogManager.getLogger(NettyHttpRequestEncoderTracingHandler.class);
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
try {
if (!TypeUtils.isHttpRequest(msg)) {
return;
}
AbstractSpan lastSpan = ctx.channel().attr(AttributeKeys.HTTP_CLIENT_SPAN).getAndSet(null);
if (null != lastSpan) {
ContextManager.stopSpan(lastSpan);
}
HttpRequest request = (HttpRequest) msg;
HttpHeaders headers = request.headers();
String uri = request.uri();
InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
String peer = address.getHostString() + ":" + address.getPort();
String url = peer + uri;
String method = request.method().toString();
ContextCarrier contextCarrier = new ContextCarrier();
AbstractSpan span = ContextManager.createExitSpan(NettyConstants.NETTY_HTTP_OPERATION_PREFIX + uri, contextCarrier, peer);
for (CarrierItem item = contextCarrier.items(); item.hasNext(); ) {
item = item.next();
headers.add(AsciiString.of(item.getHeadKey()), item.getHeadValue());
}
ContextSnapshot contextSnapshot = ctx.channel().attr(AttributeKeys.CONTEXT_SNAPSHOT_ATTRIBUTE_KEY).get();
if (contextSnapshot != null) {
ContextManager.continued(contextSnapshot);
}
span.prepareForAsync();
SpanLayer.asHttp(span);
span.setPeer(peer);
span.setComponent(ComponentsDefine.NETTY_HTTP);
boolean sslFlag = ctx.channel().pipeline().context(SslHandler.class) != null;
Tags.URL.set(span, sslFlag ? NettyConstants.HTTPS_PROTOCOL_PREFIX + url : NettyConstants.HTTP_PROTOCOL_PREFIX + url);
Tags.HTTP.METHOD.set(span, request.method().name());
if (NettyHttpPluginConfig.Plugin.NettyHttp.COLLECT_REQUEST_BODY) {
if (TypeUtils.isLastHttpContent(msg)) {
HttpDataCollectUtils.collectHttpRequestBody(request.headers(), ((LastHttpContent) msg).content(), span);
}
}
ContextManager.stopSpan(span);
ctx.channel().attr(AttributeKeys.HTTP_CLIENT_SPAN).set(span);
} catch (Exception e) {
LOGGER.error("Fail to trace netty http request", e);
} finally {
try {
ctx.write(msg, promise);
} catch (Throwable throwable) {
AbstractSpan span = ctx.channel().attr(AttributeKeys.HTTP_CLIENT_SPAN).getAndSet(null);
if (span != null) {
span.errorOccurred();
span.log(throwable);
Tags.HTTP_RESPONSE_STATUS_CODE.set(span, 500);
span.asyncFinish();
}
throw throwable;
}
}
}
}

View File

@ -0,0 +1,103 @@
/*
* 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.handler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
import org.apache.skywalking.apm.plugin.netty.http.utils.TypeUtils;
@ChannelHandler.Sharable
public class NettyHttpResponseDecoderTracingHandler extends ChannelInboundHandlerAdapter {
private static final ILog LOGGER = LogManager.getLogger(NettyHttpResponseDecoderTracingHandler.class);
private static class SingletonHolder {
private static final NettyHttpResponseDecoderTracingHandler INSTANCE = new NettyHttpResponseDecoderTracingHandler();
}
public static NettyHttpResponseDecoderTracingHandler getInstance() {
return NettyHttpResponseDecoderTracingHandler.SingletonHolder.INSTANCE;
}
private NettyHttpResponseDecoderTracingHandler() {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
if (!TypeUtils.isHttpResponse(msg)) {
return;
}
HttpResponse response = (HttpResponse) msg;
int code = response.status().code();
if (HttpResponseStatus.CONTINUE.code() == code) {
return;
}
Channel channel = ctx.channel();
AbstractSpan span = channel.attr(AttributeKeys.HTTP_CLIENT_SPAN).getAndSet(null);
if (span == null) {
return;
}
Tags.HTTP_RESPONSE_STATUS_CODE.set(span, code);
if (code >= 400) {
span.errorOccurred();
}
span.asyncFinish();
} catch (Exception e) {
LOGGER.error("Fail to trace netty http response", e);
} finally {
ctx.fireChannelRead(msg);
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// to close span in some case there is no response.
AbstractSpan span = ctx.channel().attr(AttributeKeys.HTTP_CLIENT_SPAN).getAndSet(null);
if (span != null) {
span.asyncFinish();
}
super.channelInactive(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
AbstractSpan span = ctx.channel().attr(AttributeKeys.HTTP_CLIENT_SPAN).getAndSet(null);
if (span != null) {
span.errorOccurred().log(cause);
Tags.HTTP_RESPONSE_STATUS_CODE.set(span, 500);
span.asyncFinish();
}
super.exceptionCaught(ctx, cause);
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.handler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.plugin.netty.http.common.AttributeKeys;
import org.apache.skywalking.apm.plugin.netty.http.utils.TypeUtils;
@ChannelHandler.Sharable
public class NettyHttpResponseEncoderTracingHandler extends ChannelOutboundHandlerAdapter {
private static final ILog LOGGER = LogManager.getLogger(NettyHttpResponseEncoderTracingHandler.class);
private static class SingletonHolder {
private static final NettyHttpResponseEncoderTracingHandler INSTANCE = new NettyHttpResponseEncoderTracingHandler();
}
public static NettyHttpResponseEncoderTracingHandler getInstance() {
return NettyHttpResponseEncoderTracingHandler.SingletonHolder.INSTANCE;
}
private NettyHttpResponseEncoderTracingHandler() {
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
try {
if (!TypeUtils.isHttpResponse(msg)) {
return;
}
HttpResponse response = (HttpResponse) msg;
int code = response.status().code();
if (HttpResponseStatus.CONTINUE.code() == code) {
return;
}
Channel channel = ctx.channel();
AbstractSpan span = channel.attr(AttributeKeys.HTTP_SERVER_SPAN).getAndSet(null);
if (span == null) {
return;
}
Tags.HTTP_RESPONSE_STATUS_CODE.set(span, code);
if (code >= 400) {
span.errorOccurred();
}
span.asyncFinish();
} catch (Exception e) {
LOGGER.error("Fail to trace netty http response", e);
} finally {
ctx.write(msg, promise);
}
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.utils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.plugin.netty.http.config.NettyHttpPluginConfig;
import org.apache.skywalking.apm.util.StringUtil;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class HttpDataCollectUtils {
private static final ILog LOGGER = LogManager.getLogger(HttpDataCollectUtils.class);
public static void collectHttpRequestBody(HttpHeaders headers, ByteBuf content, AbstractSpan span) {
try {
if (headers == null || content == null || span == null) {
return;
}
if (Unpooled.EMPTY_BUFFER.equals(content)) {
return;
}
String contentTypeValue = headers.get(HttpHeaderNames.CONTENT_TYPE);
boolean needCollectHttpBody = false;
for (String contentType : NettyHttpPluginConfig.Plugin.NettyHttp.SUPPORTED_CONTENT_TYPES_PREFIX.split(",")) {
if (contentTypeValue.startsWith(contentType)) {
needCollectHttpBody = true;
break;
}
}
if (needCollectHttpBody) {
String bodyStr = content.toString(getCharsetFromContentType(
headers.get(HttpHeaderNames.CONTENT_TYPE)));
bodyStr = NettyHttpPluginConfig.Plugin.NettyHttp.FILTER_LENGTH_LIMIT > 0 ?
StringUtil.cut(bodyStr, NettyHttpPluginConfig.Plugin.NettyHttp.FILTER_LENGTH_LIMIT) : bodyStr;
Tags.HTTP.BODY.set(span, bodyStr);
}
} catch (Exception e) {
LOGGER.error("Fail to collect netty http request body", e);
}
}
private static Charset getCharsetFromContentType(String contentType) {
String[] parts = contentType.split(";");
for (String part : parts) {
part = part.trim();
if (part.startsWith("charset=")) {
return Charset.forName(part.substring("charset=".length()));
}
}
return StandardCharsets.UTF_8;
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.utils;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.DefaultLastHttpContent;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.LastHttpContent;
public class TypeUtils {
public static boolean isHttpResponse(Object obj) {
Class<?> objClass = obj.getClass();
if (objClass == DefaultFullHttpResponse.class || objClass == DefaultHttpResponse.class) {
return true;
}
return obj instanceof HttpResponse;
}
public static boolean isHttpRequest(Object msg) {
Class<?> objClass = msg.getClass();
if (objClass == DefaultFullHttpRequest.class || objClass == DefaultHttpRequest.class) {
return true;
}
return msg instanceof HttpRequest;
}
public static boolean isLastHttpContent(Object msg) {
Class<?> objClass = msg.getClass();
if (objClass == DefaultLastHttpContent.class) {
return true;
}
return msg instanceof LastHttpContent;
}
public static boolean isFullHttpRequest(Object obj) {
Class<?> objClass = obj.getClass();
if (objClass == DefaultFullHttpRequest.class) {
return true;
}
return obj instanceof FullHttpRequest;
}
}

View File

@ -0,0 +1,23 @@
# 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.
netty-http-4.1.x=org.apache.skywalking.apm.plugin.netty.http.define.HttpRequestEncoderInstrumentation
netty-http-4.1.x=org.apache.skywalking.apm.plugin.netty.http.define.HttpResponseDecoderInstrumentation
netty-http-4.1.x=org.apache.skywalking.apm.plugin.netty.http.define.HttpRequestDecoderInstrumentation
netty-http-4.1.x=org.apache.skywalking.apm.plugin.netty.http.define.HttpResponseEncoderInstrumentation
netty-http-4.1.x=org.apache.skywalking.apm.plugin.netty.http.define.ChannelPipelineInstrumentation
netty-http-4.1.x=org.apache.skywalking.apm.plugin.netty.http.define.ChannelHandlerInstrumentation
netty-http-4.1.x=org.apache.skywalking.apm.plugin.netty.http.define.ChannelHandlerContextInstrumentation

View File

@ -58,6 +58,7 @@
<module>shenyu-2.4.x-plugin</module>
<module>trace-sampler-cpu-policy-plugin</module>
<module>nacos-client-2.x-plugin</module>
<module>netty-http-4.1.x-plugin</module>
</modules>
<dependencies>

View File

@ -23,4 +23,5 @@ Now, we have the following known optional plugins.
* Plugin of Apache ShenYu(incubating) Gateway 2.4.x in optional plugin folder. Please only activate this plugin when you install agent in Apache ShenYu Gateway.
* Plugin of trace sampler CPU policy in the optional plugin folder. Please only activate this plugin when you need to disable trace collecting when the agent process CPU usage is too high(over threshold).
* Plugin for Spring 6.x and RestTemplate 6.x are in the optional plugin folder. Spring 6 requires Java 17 but SkyWalking is still compatible with Java 8. So, we put it in the optional plugin folder.
* Plugin of nacos-client 2.x lib in optional plugin folder.The reason is many business irrelevant traces are generated, which cause extra payload to agents and backends, also spend more CPU, memory and network.
* Plugin of nacos-client 2.x lib in optional plugin folder. The reason is many business irrelevant traces are generated, which cause extra payload to agents and backends, also spend more CPU, memory and network.
* Plugin of netty-http 4.1.x lib in optional plugin folder. The reason is some frameworks use Netty HTTP as kernel, which could double the unnecessary spans and create incorrect RPC relative metrics.

View File

@ -70,6 +70,7 @@
- mysql-8.x
- nacos-client-2.x
- netty-socketio
- netty-http-4.1.x
- nutz-http-1.x
- nutz-mvc-annotation-1.x
- okhttp-3.x

View File

@ -25,6 +25,7 @@ metrics based on the tracing data.
* [Jersey REST framework](https://github.com/eclipse-ee4j/jersey) 2.x -> 3.x
* [Grizzly](https://github.com/eclipse-ee4j/grizzly) 2.3.x -> 4.x
* [WebSphere Liberty](https://github.com/OpenLiberty/open-liberty) 23.x
* [Netty HTTP](https://github.com/netty/netty) 4.1.x (Optional²)
* HTTP Client
* [Feign](https://github.com/OpenFeign/feign) 9.x
* [Netflix Spring Cloud Feign](https://github.com/spring-cloud/spring-cloud-openfeign) 1.1.x -> 2.x

View File

@ -127,7 +127,11 @@ This is the properties list supported in `agent/config/agent.config`.
| `plugin.ehcache.operation_mapping_write` | Specify which command should be converted to `write` operation | SW_PLUGIN_EHCACHE_OPERATION_MAPPING_WRITE | `get,getAll,getQuiet,getKeys,getKeysWithExpiryCheck,getKeysNoDuplicateCheck,releaseRead,tryRead,getWithLoader,getAll,loadAll,getAllWithLoader` |
| `plugin.ehcache.operation_mapping_read` | Specify which command should be converted to `read` operation | SW_PLUGIN_EHCACHE_OPERATION_MAPPING_READ | `tryRemoveImmediately,remove,removeAndReturnElement,removeAll,removeQuiet,removeWithWriter,put,putAll,replace,removeQuiet,removeWithWriter,removeElement,removeAll,putWithWriter,putQuiet,putIfAbsent,putIfAbsent` |
| `plugin.guavacache.operation_mapping_write` | Specify which command should be converted to `write` operation | SW_PLUGIN_GUAVACACHE_OPERATION_MAPPING_WRITE | `getIfPresent,get,getAllPresent,size` |
| `plugin.guavacache.operation_mapping_read` | Specify which command should be converted to `read` operation | SW_PLUGIN_GUAVACACHE_OPERATION_MAPPING_READ | `put,putAll,invalidate,invalidateAll,invalidateAll,cleanUp` |
| `plugin.guavacache.operation_mapping_read` | Specify which command should be converted to `read` operation | SW_PLUGIN_GUAVACACHE_OPERATION_MAPPING_READ | `put,putAll,invalidate,invalidateAll,invalidateAll,cleanUp`
| `plugin.nettyhttp.collect_request_body` | This config item controls that whether the Netty-http plugin should collect the http body of the request. | SW_PLUGIN_NETTY_HTTP_COLLECT_REQUEST_BODY | `false` |
| `plugin.nettyhttp.filter_length_limit` | When `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. | SW_PLUGIN_NETTY_HTTP_FILTER_LENGTH_LIMIT | `1024` |
| `plugin.nettyhttp.supported_content_types_prefix` | When `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 `,` | SW_PLUGIN_NETTY_HTTP_SUPPORTED_CONTENT_TYPES_PREFIX | `application/json,text/` |
|
# Reset Collection/Map type configurations as empty collection.

View File

@ -0,0 +1,21 @@
#!/bin/bash
#
# 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.
home="$(cd "$(dirname $0)"; pwd)"
java -Dskywalking.plugin.nettyhttp.collect_request_body=true -jar ${agent_opts} ${home}/../libs/netty-http-4.1.x-scenario.jar &

View File

@ -0,0 +1,81 @@
# 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.
segmentItems:
- serviceName: netty-http-4.1.x-scenario
segmentSize: gt 0
segments:
- segmentId: not null
spans:
- operationName: Netty-http:/user
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: not null
endTime: not null
componentId: 151
isError: false
spanType: Entry
peer: ''
skipAnalysis: 'false'
tags:
- { key: http.method, value: POST }
- { key: url, value: https://127.0.0.1:8070/user }
- { key: http.body, value: "{\"name\":\"david\",\"age\":30}" }
- { key: http.status_code, value: '200' }
refs:
- { parentEndpoint: Netty-http:/user, networkAddress: 'localhost:8070',
refType: CrossProcess, parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
null, parentService: netty-http-4.1.x-scenario, traceId: not null }
- segmentId: not null
spans:
- operationName: Netty-http:/user
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: not null
endTime: not null
componentId: 151
isError: false
spanType: Exit
peer: not null
skipAnalysis: 'false'
tags:
- { key: url, value: https://localhost:8070/user }
- { key: http.method, value: POST }
- { key: http.body, value: "{\"name\":\"david\",\"age\":30}" }
- { key: http.status_code, value: '200' }
refs:
- { parentEndpoint: GET:/case/netty-http-4.1.x-case, networkAddress: '',
refType: CrossThread, parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
null, parentService: netty-http-4.1.x-scenario, traceId: not null }
- segmentId: not null
spans:
- operationName: GET:/case/netty-http-4.1.x-case
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: not null
endTime: not null
componentId: 14
isError: false
spanType: Entry
peer: ''
tags:
- { key: url, value: not null }
- { key: http.method, value: GET }
- { key: http.status_code, value: '200' }
skipAnalysis: 'false'

View File

@ -0,0 +1,22 @@
# 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.
type: jvm
entryService: http://localhost:8080/netty-http-4.1.x-scenario/case/netty-http-4.1.x-case
healthCheck: http://localhost:8080/netty-http-4.1.x-scenario/case/healthCheck
startScript: ./bin/startup.sh
runningMode: with_optional
withPlugins: apm-netty-http-4.1.x-plugin-*.jar

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.skywalking</groupId>
<artifactId>netty-http-4.1.x-scenario</artifactId>
<version>1.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<compiler.version>1.8</compiler.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<spring.boot.version>2.1.6.RELEASE</spring.boot.version>
<test.framework.version>4.1.51.Final</test.framework.version>
</properties>
<name>skywalking-netty-http-scenario</name>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${test.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
</dependencies>
<build>
<finalName>netty-http-4.1.x-scenario</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.9.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${compiler.version}</source>
<target>${compiler.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
<outputDirectory>./target/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>./bin</directory>
<fileMode>0775</fileMode>
</fileSet>
</fileSets>
<files>
<file>
<source>${project.build.directory}/netty-http-4.1.x-scenario.jar</source>
<outputDirectory>./libs</outputDirectory>
<fileMode>0775</fileMode>
</file>
</files>
</assembly>

View File

@ -0,0 +1,30 @@
/*
* 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 test.apache.skywalking.apm.testcase.netty.http;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,49 @@
/*
* 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 test.apache.skywalking.apm.testcase.netty.http.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import test.apache.skywalking.apm.testcase.netty.http.core.ClientService;
import test.apache.skywalking.apm.testcase.netty.http.core.ServerService;
@RestController
@RequestMapping("/case")
public class CaseController {
@RequestMapping("/netty-http-4.1.x-case")
@ResponseBody
public String nettyCase() throws Exception {
ClientService.start();
return "Success";
}
@RequestMapping("/healthCheck")
@ResponseBody
public String healthCheck() {
try {
ServerService.start();
} catch (Exception e) {
return "fail";
}
return "success";
}
}

View File

@ -0,0 +1,87 @@
/*
* 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 test.apache.skywalking.apm.testcase.netty.http.core;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import test.apache.skywalking.apm.testcase.netty.http.handler.UserClientHandler;
import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.charset.StandardCharsets;
public class ClientService {
public static void start() {
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
ChannelFuture channelFuture = new Bootstrap()
.group(workerGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline().addLast(sslContext.newHandler(nioSocketChannel.alloc()));
nioSocketChannel.pipeline().addLast(new HttpClientCodec());
nioSocketChannel.pipeline().addLast(new HttpObjectAggregator(512 * 1024));
nioSocketChannel.pipeline().addLast(new UserClientHandler());
}
})
.connect(new InetSocketAddress("localhost", 8070)).sync();
Channel channel = channelFuture.channel();
URI uri = new URI("/user");
String jsonBody = "{\"name\":\"david\",\"age\":30}";
FullHttpRequest request = new DefaultFullHttpRequest(
HttpVersion.HTTP_1_1,
HttpMethod.POST,
uri.toASCIIString(),
Unpooled.wrappedBuffer(jsonBody.getBytes(StandardCharsets.UTF_8)));
request.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON);
request.headers().set(HttpHeaderNames.EXPECT, HttpHeaderValues.CONTINUE);
request.headers().set(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes());
channel.writeAndFlush(request);
channel.closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
}
}
}

View File

@ -0,0 +1,62 @@
/*
* 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 test.apache.skywalking.apm.testcase.netty.http.core;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import test.apache.skywalking.apm.testcase.netty.http.handler.UserServerHandler;
public class ServerService {
public static void start() throws Exception {
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
try {
SelfSignedCertificate certificate = new SelfSignedCertificate();
SslContext sslContext = SslContextBuilder.forServer(certificate.certificate(), certificate.privateKey()).build();
ChannelFuture future = new ServerBootstrap()
.group(workerGroup, bossGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline().addLast(sslContext.newHandler(nioSocketChannel.alloc()));
nioSocketChannel.pipeline().addLast(new HttpServerCodec());
nioSocketChannel.pipeline().addLast(new HttpObjectAggregator(512 * 1024));
nioSocketChannel.pipeline().addLast(new UserServerHandler());
}
}).bind(8070);
future.sync();
future.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}

View File

@ -0,0 +1,45 @@
/*
* 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 test.apache.skywalking.apm.testcase.netty.http.handler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
public class UserClientHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(UserClientHandler.class);
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpResponse) {
FullHttpResponse response = (FullHttpResponse) msg;
if (HttpResponseStatus.CONTINUE.code() != response.status().code()) {
LOGGER.info("receive message from server :{}", response.content().toString(StandardCharsets.UTF_8));
ctx.channel().close();
}
}
}
}

View File

@ -0,0 +1,57 @@
/*
* 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 test.apache.skywalking.apm.testcase.netty.http.handler;
import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import java.nio.charset.StandardCharsets;
public class UserServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
if (HttpMethod.POST.equals(request.method())) {
JSONObject resultJson = new JSONObject();
resultJson.put("code", 200);
resultJson.put("message", "success");
String jsonString = resultJson.toJSONString();
FullHttpResponse response = new DefaultFullHttpResponse(
request.protocolVersion(),
HttpResponseStatus.OK,
Unpooled.wrappedBuffer(jsonString.getBytes(StandardCharsets.UTF_8)));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, jsonString.length());
ctx.writeAndFlush(response);
}
}
}

View File

@ -0,0 +1,22 @@
#
# 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.
#
#
server:
port: 8080
servlet:
context-path: /netty-http-4.1.x-scenario

View File

@ -0,0 +1,27 @@
# 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.
4.1.6.Final
4.1.16.Final
4.1.25.Final
4.1.36.Final
4.1.49.Final
4.1.58.Final
4.1.66.Final
4.1.74.Final
4.1.82.Final
4.1.90.Final
4.1.98.Final