dubbo3 plugin support (#73)

This commit is contained in:
tedli 2021-12-10 14:35:30 +08:00 committed by GitHub
parent 2557749617
commit ee5bb80fc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 2080 additions and 3 deletions

View File

@ -67,6 +67,7 @@ jobs:
- correlation-autotag-scenario
- dubbo-2.5.x-scenario
- dubbo-2.7.x-scenario
- dubbo-3.x-scenario
- ehcache-2.x-scenario
- elasticsearch-5.x-scenario
- elasticsearch-6.x-scenario

View File

@ -14,6 +14,7 @@ Release Notes.
* Avoid `ProfileTaskChannelService.addProfilingSnapshot` throw IllegalStateException(Queue full)
* Increase `ProfileTaskChannelService.snapshotQueue` default size from 50 to 4500
* Support 2.8 and 2.9 of pulsar client.
* Add dubbo 3.x plugin.
#### Documentation

View File

@ -19,11 +19,16 @@ package org.apache.skywalking.apm.plugin.asf.dubbo.patch;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import java.util.Collections;
import java.util.List;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
@ -35,6 +40,11 @@ import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName
* to ensure the correct compilation of the code.
*/
public class WrapperInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
private static final String CONTEXT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContext";
private static final String GET_SERVER_CONTEXT_METHOD_NAME = "getServerContext";
@Override
public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
return new StaticMethodsInterceptPoint[] {
@ -61,4 +71,14 @@ public class WrapperInstrumentation extends ClassStaticMethodsEnhancePluginDefin
protected ClassMatch enhanceClass() {
return byName("org.apache.dubbo.common.bytecode.Wrapper");
}
@Override
protected List<WitnessMethod> witnessMethods() {
return Collections.singletonList(new WitnessMethod(
CONTEXT_TYPE_NAME,
named(GET_SERVER_CONTEXT_METHOD_NAME).and(
returns(named(CONTEXT_TYPE_NAME)))
));
}
}

View File

@ -14,4 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
dubbo=org.apache.skywalking.apm.plugin.asf.dubbo.patch.WrapperInstrumentation
dubbo-2.7.x=org.apache.skywalking.apm.plugin.asf.dubbo.patch.WrapperInstrumentation

View File

@ -20,13 +20,18 @@ package org.apache.skywalking.apm.plugin.asf.dubbo;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
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.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import java.util.Collections;
import java.util.List;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns;
public class DubboInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
@ -34,6 +39,10 @@ public class DubboInstrumentation extends ClassInstanceMethodsEnhancePluginDefin
private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.asf.dubbo.DubboInterceptor";
private static final String CONTEXT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContext";
private static final String GET_SERVER_CONTEXT_METHOD_NAME = "getServerContext";
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
@ -65,4 +74,14 @@ public class DubboInstrumentation extends ClassInstanceMethodsEnhancePluginDefin
}
};
}
@Override
protected List<WitnessMethod> witnessMethods() {
return Collections.singletonList(new WitnessMethod(
CONTEXT_TYPE_NAME,
named(GET_SERVER_CONTEXT_METHOD_NAME).and(
returns(named(CONTEXT_TYPE_NAME)))
));
}
}

View File

@ -14,4 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
dubbo=org.apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation
dubbo-2.7.x=org.apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation

View File

@ -0,0 +1,44 @@
<?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>
<artifactId>apm-sdk-plugin</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>8.9.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-3.x-conflict-patch</artifactId>
<name>apm-dubbo-3.x-conflict-path</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<dubbo.version>3.0.0</dubbo.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,329 @@
/*
* 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.asf.dubbo3.patch;
import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.common.bytecode.NoSuchPropertyException;
import org.apache.dubbo.common.bytecode.Wrapper;
import org.apache.dubbo.common.utils.ClassHelper;
import org.apache.dubbo.common.utils.ReflectUtils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
public class MakeWrapperInterceptor implements StaticMethodsAroundInterceptor {
private static final AtomicLong WRAPPER_CLASS_COUNTER = new AtomicLong(0);
@Override
public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
MethodInterceptResult result) {
Class wrapperClass = (Class<?>) allArguments[0];
if (EnhancedInstance.class.isAssignableFrom(wrapperClass)) {
result.defineReturnValue(makeWrapper(wrapperClass));
}
}
@Override
public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
Object ret) {
return ret;
}
@Override
public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
Throwable t) {
}
private static Wrapper makeWrapper(Class<?> c) {
if (c.isPrimitive())
throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
String name = c.getName();
ClassLoader cl = ClassHelper.getClassLoader(c);
StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
StringBuilder c3 = new StringBuilder(
"public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class
.getName() + "{ ");
c1.append(name)
.append(" w; try{ w = ((")
.append(name)
.append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
c2.append(name)
.append(" w; try{ w = ((")
.append(name)
.append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
c3.append(name)
.append(" w; try{ w = ((")
.append(name)
.append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
Map<String, Class<?>> pts = new HashMap<String, Class<?>>(); // <property name, property types>
Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
List<String> mns = new ArrayList<String>(); // method names.
List<String> dmns = new ArrayList<String>(); // declaring method names.
// get all public field.
for (Field f : c.getFields()) {
String fn = f.getName();
Class<?> ft = f.getType();
if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()))
continue;
c1.append(" if( $2.equals(\"")
.append(fn)
.append("\") ){ w.")
.append(fn)
.append("=")
.append(arg(ft, "$3"))
.append("; return; }");
c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
pts.put(fn, ft);
}
Method[] methods = c.getMethods();
// get all public method.
boolean hasMethod = hasMethods(methods);
if (hasMethod) {
c3.append(" try{");
}
for (Method m : methods) {
// ignore Object's method
// ignore EnhanceInstance's method
if (m.getDeclaringClass() == Object.class || "getSkyWalkingDynamicField".equals(
m.getName()) || "setSkyWalkingDynamicField"
.equals(m.getName())) {
continue;
}
String mn = m.getName();
c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
int len = m.getParameterTypes().length;
c3.append(" && ").append(" $3.length == ").append(len);
boolean override = false;
for (Method m2 : methods) {
if (!m.equals(m2) && m.getName().equals(m2.getName())) {
override = true;
break;
}
}
if (override) {
if (len > 0) {
for (int l = 0; l < len; l++) {
c3.append(" && ")
.append(" $3[")
.append(l)
.append("].getName().equals(\"")
.append(m.getParameterTypes()[l].getName())
.append("\")");
}
}
}
c3.append(" ) { ");
if (m.getReturnType() == Void.TYPE)
c3.append(" w.")
.append(mn)
.append('(')
.append(args(m.getParameterTypes(), "$4"))
.append(");")
.append(" return null;");
else
c3.append(" return ($w)w.")
.append(mn)
.append('(')
.append(args(m.getParameterTypes(), "$4"))
.append(");");
c3.append(" }");
mns.add(mn);
if (m.getDeclaringClass() == c)
dmns.add(mn);
ms.put(ReflectUtils.getDesc(m), m);
}
if (hasMethod) {
c3.append(" } catch(Throwable e) { ");
c3.append(" throw new java.lang.reflect.InvocationTargetException(e); ");
c3.append(" }");
}
c3.append(
" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c
.getName() + ".\"); }");
// deal with get/set method.
Matcher matcher;
for (Map.Entry<String, Method> entry : ms.entrySet()) {
String md = entry.getKey();
Method method = (Method) entry.getValue();
if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
String pn = propertyName(matcher.group(1));
c2.append(" if( $2.equals(\"")
.append(pn)
.append("\") ){ return ($w)w.")
.append(method.getName())
.append("(); }");
pts.put(pn, method.getReturnType());
} else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
String pn = propertyName(matcher.group(1));
c2.append(" if( $2.equals(\"")
.append(pn)
.append("\") ){ return ($w)w.")
.append(method.getName())
.append("(); }");
pts.put(pn, method.getReturnType());
} else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
Class<?> pt = method.getParameterTypes()[0];
String pn = propertyName(matcher.group(1));
c1.append(" if( $2.equals(\"")
.append(pn)
.append("\") ){ w.")
.append(method.getName())
.append("(")
.append(arg(pt, "$3"))
.append("); return; }");
pts.put(pn, pt);
}
}
c1.append(
" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c
.getName() + ".\"); }");
c2.append(
" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c
.getName() + ".\"); }");
// make class
long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
ClassGenerator cc = ClassGenerator.newInstance(cl);
cc.setClassName((Modifier.isPublic(
c.getModifiers()) ? Wrapper.class.getName() + "_swEnhance" : c.getName() + "$sw$_swEnhance") + id);
cc.setSuperClass(Wrapper.class);
cc.addDefaultConstructor();
cc.addField("public static String[] pns;"); // property name array.
cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
cc.addField("public static String[] mns;"); // all method name array.
cc.addField("public static String[] dmns;"); // declared method name array.
for (int i = 0, len = ms.size(); i < len; i++)
cc.addField("public static Class[] mts" + i + ";");
cc.addMethod("public String[] getPropertyNames(){ return pns; }");
cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
cc.addMethod("public String[] getMethodNames(){ return mns; }");
cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
cc.addMethod(c1.toString());
cc.addMethod(c2.toString());
cc.addMethod(c3.toString());
try {
Class<?> wc = cc.toClass();
// setup static field.
wc.getField("pts").set(null, pts);
wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
wc.getField("mns").set(null, mns.toArray(new String[0]));
wc.getField("dmns").set(null, dmns.toArray(new String[0]));
int ix = 0;
for (Method m : ms.values())
wc.getField("mts" + ix++).set(null, m.getParameterTypes());
return (Wrapper) wc.getDeclaredConstructor().newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
cc.release();
ms.clear();
mns.clear();
dmns.clear();
}
}
private static String args(Class<?>[] cs, String name) {
int len = cs.length;
if (len == 0)
return "";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++) {
if (i > 0)
sb.append(',');
sb.append(arg(cs[i], name + "[" + i + "]"));
}
return sb.toString();
}
private static String propertyName(String pn) {
return pn.length() == 1 || Character.isLowerCase(pn.charAt(1)) ? Character.toLowerCase(
pn.charAt(0)) + pn.substring(1) : pn;
}
private static boolean hasMethods(Method[] methods) {
if (methods == null || methods.length == 0) {
return false;
}
for (Method m : methods) {
if (m.getDeclaringClass() != Object.class && !"getSkyWalkingDynamicField".equals(
m.getName()) && !"setSkyWalkingDynamicField"
.equals(m.getName())) {
return true;
}
}
return false;
}
private static String arg(Class<?> cl, String name) {
if (cl.isPrimitive()) {
if (cl == Boolean.TYPE)
return "((Boolean)" + name + ").booleanValue()";
if (cl == Byte.TYPE)
return "((Byte)" + name + ").byteValue()";
if (cl == Character.TYPE)
return "((Character)" + name + ").charValue()";
if (cl == Double.TYPE)
return "((Number)" + name + ").doubleValue()";
if (cl == Float.TYPE)
return "((Number)" + name + ").floatValue()";
if (cl == Integer.TYPE)
return "((Number)" + name + ").intValue()";
if (cl == Long.TYPE)
return "((Number)" + name + ").longValue()";
if (cl == Short.TYPE)
return "((Number)" + name + ").shortValue()";
throw new RuntimeException("Unknown primitive type: " + cl.getName());
}
return "(" + ReflectUtils.getName(cl) + ")" + name;
}
}

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 org.apache.skywalking.apm.plugin.asf.dubbo3.patch;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import java.util.Collections;
import java.util.List;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
/**
* The dubbo conflict plugin resolver the problem about the wrapper class generated by Dubbo core cannot be compiled
* successfully. As we known, The wrapper class traverses all the methods. In usual, it works unless this class has been
* enhanced by Skywalking. The javasist cannot found the `EnhanceInstance` method when generate.
* <p>
* The plugin excludes {@link org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance} methods
* to ensure the correct compilation of the code.
*/
public class WrapperInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
private static final String CONTEXT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContext";
private static final String GET_SERVER_CONTEXT_METHOD_NAME = "getServerContext";
private static final String CONTEXT_ATTACHMENT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContextAttachment";
@Override
public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
return new StaticMethodsInterceptPoint[] {
new StaticMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("makeWrapper");
}
@Override
public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.asf.dubbo3.patch.MakeWrapperInterceptor";
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
@Override
protected ClassMatch enhanceClass() {
return byName("org.apache.dubbo.common.bytecode.Wrapper");
}
@Override
protected List<WitnessMethod> witnessMethods() {
return Collections.singletonList(
new WitnessMethod(
CONTEXT_TYPE_NAME,
named(GET_SERVER_CONTEXT_METHOD_NAME).and(
returns(named(CONTEXT_ATTACHMENT_TYPE_NAME)))
));
}
}

View File

@ -0,0 +1,17 @@
# 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.
dubbo-3.x=org.apache.skywalking.apm.plugin.asf.dubbo3.patch.WrapperInstrumentation

View File

@ -0,0 +1,46 @@
<!--
~ 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>
<artifactId>apm-sdk-plugin</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>8.9.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-dubbo-3.x-plugin</artifactId>
<packaging>jar</packaging>
<name>dubbo-3.x-plugin</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<dubbo.version>3.0.0</dubbo.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

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.
*
*/
package org.apache.skywalking.apm.plugin.asf.dubbo3;
public class DubboConsumerInstrumentation extends DubboInstrumentationBase {
public DubboConsumerInstrumentation() {
super(CONSUMER_ENHANCE_CLASS);
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.asf.dubbo3;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
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.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import java.util.Collections;
import java.util.List;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns;
public class DubboInstrumentationBase extends ClassInstanceMethodsEnhancePluginDefine {
public static final String PROVIDER_ENHANCE_CLASS = "org.apache.dubbo.monitor.support.MonitorFilter";
public static final String CONSUMER_ENHANCE_CLASS = "org.apache.dubbo.monitor.support.MonitorClusterFilter";
public static final String INTERCEPT_POINT_METHOD = "invoke";
public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.asf.dubbo3.DubboInterceptor";
public static final String CONTEXT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContext";
public static final String GET_SERVER_CONTEXT_METHOD_NAME = "getServerContext";
public static final String CONTEXT_ATTACHMENT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContextAttachment";
private final String enhanceClassName;
public DubboInstrumentationBase(String enhanceClassName) {
this.enhanceClassName = enhanceClassName;
}
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(enhanceClassName);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return null;
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(INTERCEPT_POINT_METHOD);
}
@Override
public String getMethodsInterceptor() {
return INTERCEPT_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
@Override
protected List<WitnessMethod> witnessMethods() {
return Collections.singletonList(
new WitnessMethod(
CONTEXT_TYPE_NAME,
named(GET_SERVER_CONTEXT_METHOD_NAME).and(
returns(named(CONTEXT_ATTACHMENT_TYPE_NAME)))
));
}
}

View File

@ -0,0 +1,217 @@
/*
* 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.asf.dubbo3;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcContextAttachment;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcServiceContext;
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.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.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.util.StringUtil;
import java.lang.reflect.Method;
/**
* {@link DubboInterceptor} define how to enhance class {@link org.apache.dubbo.monitor.support.MonitorFilter#invoke(Invoker,
* Invocation)}. the trace context transport to the provider side by {@link RpcContext#getServerAttachment}.but all the
* version of dubbo framework below 3.0.0 don't support {@link RpcContext#getClientAttachment}, we support another way
* to support it.
*/
public class DubboInterceptor implements InstanceMethodsAroundInterceptor {
public static final String ARGUMENTS = "arguments";
/**
* <h2>Consumer:</h2> The serialized trace context data will
* inject to the {@link RpcContext#getClientAttachment} for transport to provider side.
* <p>
* <h2>Provider:</h2> The serialized trace context data will extract from
* {@link RpcContext#getServerAttachment}. current trace segment will ref if the serialize context data is not
* null.
*/
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
Invoker invoker = (Invoker) allArguments[0];
Invocation invocation = (Invocation) allArguments[1];
RpcServiceContext serviceContext = RpcContext.getServiceContext();
boolean isConsumer;
URL url = serviceContext.getUrl();
if (url == null) {
url = serviceContext.getConsumerUrl();
isConsumer = url != null;
} else {
isConsumer = serviceContext.isConsumerSide();
}
RpcContextAttachment attachment = isConsumer ? RpcContext.getClientAttachment() : RpcContext.getServerAttachment();
URL requestURL = invoker.getUrl();
AbstractSpan span;
final String host = requestURL.getHost();
final int port = requestURL.getPort();
boolean needCollectArguments;
int argumentsLengthThreshold;
if (isConsumer) {
final ContextCarrier contextCarrier = new ContextCarrier();
span = ContextManager.createExitSpan(
generateOperationName(requestURL, invocation), contextCarrier, host + ":" + port);
//invocation.getAttachments().put("contextData", contextDataStr);
//@see https://github.com/alibaba/dubbo/blob/dubbo-2.5.3/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java#L154-L161
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
attachment.setAttachment(next.getHeadKey(), next.getHeadValue());
if (invocation.getAttachments().containsKey(next.getHeadKey())) {
invocation.getAttachments().remove(next.getHeadKey());
}
}
needCollectArguments = DubboPluginConfig.Plugin.Dubbo.COLLECT_CONSUMER_ARGUMENTS;
argumentsLengthThreshold = DubboPluginConfig.Plugin.Dubbo.CONSUMER_ARGUMENTS_LENGTH_THRESHOLD;
} else {
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
next.setHeadValue(attachment.getAttachment(next.getHeadKey()));
}
span = ContextManager.createEntrySpan(generateOperationName(requestURL, invocation), contextCarrier);
span.setPeer(attachment.getRemoteAddressString());
needCollectArguments = DubboPluginConfig.Plugin.Dubbo.COLLECT_PROVIDER_ARGUMENTS;
argumentsLengthThreshold = DubboPluginConfig.Plugin.Dubbo.PROVIDER_ARGUMENTS_LENGTH_THRESHOLD;
}
Tags.URL.set(span, generateRequestURL(requestURL, invocation));
collectArguments(needCollectArguments, argumentsLengthThreshold, span, invocation);
span.setComponent(ComponentsDefine.DUBBO);
SpanLayer.asRPCFramework(span);
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
Result result = (Result) ret;
try {
if (result != null && result.getException() != null) {
dealException(result.getException());
}
} catch (RpcException e) {
dealException(e);
}
ContextManager.stopSpan();
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
dealException(t);
}
/**
* Log the throwable, which occurs in Dubbo RPC service.
*/
private void dealException(Throwable throwable) {
AbstractSpan span = ContextManager.activeSpan();
span.log(throwable);
}
/**
* Format operation name. e.g. org.apache.skywalking.apm.plugin.test.Test.test(String)
*
* @return operation name.
*/
private String generateOperationName(URL requestURL, Invocation invocation) {
StringBuilder operationName = new StringBuilder();
String groupStr = requestURL.getParameter(CommonConstants.GROUP_KEY);
groupStr = StringUtil.isEmpty(groupStr) ? "" : groupStr + "/";
operationName.append(groupStr);
operationName.append(requestURL.getPath());
operationName.append("." + invocation.getMethodName() + "(");
for (Class<?> classes : invocation.getParameterTypes()) {
operationName.append(classes.getSimpleName() + ",");
}
if (invocation.getParameterTypes().length > 0) {
operationName.delete(operationName.length() - 1, operationName.length());
}
operationName.append(")");
return operationName.toString();
}
/**
* Format request url. e.g. dubbo://127.0.0.1:20880/org.apache.skywalking.apm.plugin.test.Test.test(String).
*
* @return request url.
*/
private String generateRequestURL(URL url, Invocation invocation) {
StringBuilder requestURL = new StringBuilder();
requestURL.append(url.getProtocol() + "://");
requestURL.append(url.getHost());
requestURL.append(":" + url.getPort() + "/");
requestURL.append(generateOperationName(url, invocation));
return requestURL.toString();
}
private void collectArguments(boolean needCollectArguments,
int argumentsLengthThreshold,
AbstractSpan span,
Invocation invocation) {
if (needCollectArguments && argumentsLengthThreshold > 0) {
Object[] parameters = invocation.getArguments();
if (parameters != null && parameters.length > 0) {
StringBuilder stringBuilder = new StringBuilder();
boolean first = true;
for (Object parameter : parameters) {
if (!first) {
stringBuilder.append(",");
}
stringBuilder.append(parameter);
if (stringBuilder.length() > argumentsLengthThreshold) {
stringBuilder.append("...");
break;
}
first = false;
}
span.tag(ARGUMENTS, stringBuilder.toString());
}
}
}
}

View File

@ -0,0 +1,39 @@
/*
* 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.asf.dubbo3;
import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
public class DubboPluginConfig {
public static class Plugin {
@PluginConfig(root = DubboPluginConfig.class)
public static class Dubbo {
public static boolean COLLECT_CONSUMER_ARGUMENTS = false;
public static int CONSUMER_ARGUMENTS_LENGTH_THRESHOLD = 256;
public static boolean COLLECT_PROVIDER_ARGUMENTS = false;
public static int PROVIDER_ARGUMENTS_LENGTH_THRESHOLD = 256;
}
}
}

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.
*
*/
package org.apache.skywalking.apm.plugin.asf.dubbo3;
public class DubboProviderInstrumentation extends DubboInstrumentationBase {
public DubboProviderInstrumentation() {
super(PROVIDER_ENHANCE_CLASS);
}
}

View File

@ -0,0 +1,18 @@
# 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.
dubbo-3.x=org.apache.skywalking.apm.plugin.asf.dubbo3.DubboProviderInstrumentation
dubbo-3.x=org.apache.skywalking.apm.plugin.asf.dubbo3.DubboConsumerInstrumentation

View File

@ -0,0 +1,26 @@
/*
* 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.dubbo3;
import org.apache.skywalking.apm.agent.core.boot.OverrideImplementor;
import org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService;
@OverrideImplementor(ContextManagerExtendService.class)
public class ContextManagerExtendOverrideService extends ContextManagerExtendService {
}

View File

@ -0,0 +1,242 @@
/*
* 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.dubbo3;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import java.util.List;
import org.apache.dubbo.rpc.RpcContextAttachment;
import org.apache.dubbo.rpc.RpcServiceContext;
import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService;
import org.apache.skywalking.apm.agent.core.context.SW8CarrierItem;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef;
import org.apache.skywalking.apm.agent.core.context.util.TagValuePair;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
import org.apache.skywalking.apm.agent.test.helper.SegmentRefHelper;
import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.apache.skywalking.apm.plugin.asf.dubbo3.DubboInterceptor;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.util.Assert;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
@PrepareForTest({RpcContext.class})
public class DubboInterceptorTest {
@SegmentStoragePoint
private SegmentStorage segmentStorage;
@Rule
public AgentServiceRule agentServiceRule = new AgentServiceRule();
@Mock
private EnhancedInstance enhancedInstance;
private DubboInterceptor dubboInterceptor;
@Mock
private RpcServiceContext serviceContext;
@Mock
private RpcContextAttachment contextAttachment;
@Mock
private Invoker invoker;
@Mock
private Invocation invocation;
@Mock
private MethodInterceptResult methodInterceptResult;
@Mock
private Result result;
private Object[] allArguments;
private Class[] argumentTypes;
@Before
public void setUp() throws Exception {
dubboInterceptor = new DubboInterceptor();
PowerMockito.mockStatic(RpcContext.class);
URL url = URL.valueOf("dubbo://127.0.0.1:20880/org.apache.skywalking.apm.test.TestDubboService");
when(invoker.getUrl()).thenReturn(url);
when(invocation.getMethodName()).thenReturn("test");
when(invocation.getParameterTypes()).thenReturn(new Class[] {String.class});
when(invocation.getArguments()).thenReturn(new Object[] {"abc"});
when(RpcContext.getServiceContext()).thenReturn(serviceContext);
when(serviceContext.getUrl()).thenReturn(null);
when(serviceContext.getConsumerUrl()).thenReturn(url);
when(RpcContext.getClientAttachment()).thenReturn(contextAttachment);
allArguments = new Object[] {
invoker,
invocation
};
argumentTypes = new Class[] {
invoker.getClass(),
invocation.getClass()
};
Config.Agent.SERVICE_NAME = "DubboTestCases-APP";
}
@Test
public void testServiceFromPlugin() {
PluginBootService service = ServiceManager.INSTANCE.findService(PluginBootService.class);
Assert.notNull(service);
}
@Test
public void testServiceOverrideFromPlugin() {
ContextManagerExtendService service = ServiceManager.INSTANCE.findService(ContextManagerExtendService.class);
Assert.isInstanceOf(ContextManagerExtendOverrideService.class, service);
}
@Test
public void testConsumerWithAttachment() throws Throwable {
dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
assertConsumerSpan(spans.get(0));
}
@Test
public void testConsumerWithException() throws Throwable {
dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.handleMethodException(
enhancedInstance, null, allArguments, argumentTypes, new RuntimeException());
dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
assertConsumerTraceSegmentInErrorCase(traceSegment);
}
@Test
public void testConsumerWithResultHasException() throws Throwable {
when(result.getException()).thenReturn(new RuntimeException());
dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertThat(segmentStorage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
assertConsumerTraceSegmentInErrorCase(traceSegment);
}
@Test
public void testProviderWithAttachment() throws Throwable {
when(serviceContext.getUrl()).thenReturn(
URL.valueOf("dubbo://127.0.0.1:20880/org.apache.skywalking.apm.test.TestDubboService"));
when(serviceContext.getConsumerUrl()).thenReturn(null);
when(RpcContext.getServerAttachment()).thenReturn(contextAttachment);
when(contextAttachment.getAttachment(
SW8CarrierItem.HEADER_NAME)).thenReturn(
"1-My40LjU=-MS4yLjM=-3-c2VydmljZQ==-aW5zdGFuY2U=-L2FwcA==-MTI3LjAuMC4xOjgwODA=");
dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertProvider();
}
private void assertConsumerTraceSegmentInErrorCase(TraceSegment traceSegment) {
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
assertConsumerSpan(spans.get(0));
AbstractTracingSpan span = spans.get(0);
assertThat(SpanHelper.getLogs(span).size(), is(1));
assertErrorLog(SpanHelper.getLogs(span).get(0));
}
private void assertErrorLog(LogDataEntity logData) {
assertThat(logData.getLogs().size(), is(4));
assertThat(logData.getLogs().get(0).getValue(), CoreMatchers.<Object>is("error"));
assertThat(logData.getLogs().get(1).getValue(), CoreMatchers.<Object>is(RuntimeException.class.getName()));
assertNull(logData.getLogs().get(2).getValue());
}
private void assertProvider() {
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
assertThat(SegmentHelper.getSpans(traceSegment).size(), is(1));
assertProviderSpan(SegmentHelper.getSpans(traceSegment).get(0));
assertTraceSegmentRef(traceSegment.getRef());
}
private void assertTraceSegmentRef(TraceSegmentRef actual) {
assertThat(SegmentRefHelper.getSpanId(actual), is(3));
assertThat(SegmentRefHelper.getParentServiceInstance(actual), is("instance"));
assertThat(SegmentRefHelper.getTraceSegmentId(actual), is("3.4.5"));
}
private void assertProviderSpan(AbstractTracingSpan span) {
assertCommonsAttribute(span);
assertTrue(span.isEntry());
}
private void assertConsumerSpan(AbstractTracingSpan span) {
assertCommonsAttribute(span);
assertTrue(span.isExit());
}
private void assertCommonsAttribute(AbstractTracingSpan span) {
List<TagValuePair> tags = SpanHelper.getTags(span);
assertThat(tags.size(), is(1));
assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.RPC_FRAMEWORK));
assertThat(SpanHelper.getComponentId(span), is(3));
assertThat(
tags.get(0)
.getValue(),
is("dubbo://127.0.0.1:20880/org.apache.skywalking.apm.test.TestDubboService.test(String)")
);
assertThat(span.getOperationName(), is("org.apache.skywalking.apm.test.TestDubboService.test(String)"));
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.dubbo3;
import org.apache.skywalking.apm.agent.core.boot.BootService;
public class PluginBootService implements BootService {
@Override
public void prepare() throws Throwable {
}
@Override
public void boot() throws Throwable {
}
@Override
public void onComplete() throws Throwable {
}
@Override
public void shutdown() throws Throwable {
}
}

View File

@ -0,0 +1,20 @@
#
# 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.
#
#
org.apache.skywalking.apm.plugin.dubbo3.PluginBootService
org.apache.skywalking.apm.plugin.dubbo3.ContextManagerExtendOverrideService

View File

@ -75,6 +75,8 @@
<module>canal-1.x-plugin</module>
<module>dubbo-2.7.x-plugin</module>
<module>dubbo-2.7.x-conflict-patch</module>
<module>dubbo-3.x-plugin</module>
<module>dubbo-3.x-conflict-patch</module>
<module>vertx-plugins</module>
<module>resteasy-plugin</module>
<module>solrj-7.x-plugin</module>

View File

@ -12,6 +12,8 @@
- dbcp-2.x
- druid-1.x
- dubbo
- dubbo-2.7.x
- dubbo-3.x
- ehcache-2.x
- elastic-job-2.x
- elasticjob-3.x

View File

@ -46,7 +46,7 @@ metrics based on the tracing data.
* RPC Frameworks
* [Dubbo](https://github.com/alibaba/dubbo) 2.5.4 -> 2.6.0
* [Dubbox](https://github.com/dangdangdotcom/dubbox) 2.8.4
* [Apache Dubbo](https://github.com/apache/dubbo) 2.7.0
* [Apache Dubbo](https://github.com/apache/dubbo) 2.7.x -> 3.x
* [Motan](https://github.com/weibocom/motan) 0.2.x -> 1.1.0
* [gRPC](https://github.com/grpc/grpc-java) 1.x
* [Apache ServiceComb Java Chassis](https://github.com/apache/servicecomb-java-chassis) 0.1 -> 0.5,1.x

View File

@ -0,0 +1,22 @@
#!/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.dubbo.collect_consumer_arguments=true \
-Dskywalking.plugin.dubbo.collect_provider_arguments=true -jar ${agent_opts} ${home}/../libs/dubbo-3.x-scenario.jar &

View File

@ -0,0 +1,70 @@
# 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: dubbo-3.x-scenario
segmentSize: ge 3
segments:
- segmentId: not null
spans:
- operationName: org.apache.skywalking.apm.testcase.dubbo3.services.GreetService.doBusiness(String)
parentSpanId: -1
spanId: 0
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 3
isError: false
spanType: Entry
peer: not null
tags:
- {key: url, value: not null}
- {key: arguments, value: helloWorld}
refs:
- {parentEndpoint: GET:/dubbo-3.x-scenario/case/dubbo, networkAddress: not null,
refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstance: not null, parentService: dubbo-3.x-scenario, traceId: not null}
skipAnalysis: 'false'
- segmentId: not null
spans:
- operationName: org.apache.skywalking.apm.testcase.dubbo3.services.GreetService.doBusiness(String)
parentSpanId: 0
spanId: 1
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 3
isError: false
spanType: Exit
peer: not null
tags:
- {key: url, value: not null}
- {key: arguments, value: helloWorld}
skipAnalysis: 'false'
- operationName: GET:/dubbo-3.x-scenario/case/dubbo
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: nq 0
endTime: nq 0
componentId: 1
isError: false
spanType: Entry
peer: ''
tags:
- {key: url, value: 'http://localhost:8080/dubbo-3.x-scenario/case/dubbo'}
- {key: http.method, value: GET}
skipAnalysis: 'false'

View File

@ -0,0 +1,20 @@
# 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/dubbo-3.x-scenario/case/dubbo
healthCheck: http://localhost:8080/dubbo-3.x-scenario/case/healthCheck
startScript: ./bin/startup.sh

View File

@ -0,0 +1,115 @@
<?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>dubbo-3.x-scenario</artifactId>
<version>5.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<compiler.version>1.8</compiler.version>
<spring.boot.version>2.1.6.RELEASE</spring.boot.version>
<test.framework>dubbo</test.framework>
<test.framework.version>3.0.0</test.framework.version>
</properties>
<name>skywalking-dubbo-3.x-scenario</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${test.framework.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${test.framework.version}</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<finalName>dubbo-3.x-scenario</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<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>./target/dubbo-3.x-scenario.jar</source>
<outputDirectory>./libs</outputDirectory>
<fileMode>0775</fileMode>
</file>
</files>
</assembly>

View File

@ -0,0 +1,77 @@
/*
* 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.testcase.dubbo3;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.skywalking.apm.testcase.dubbo3.services.GreetService;
import org.apache.skywalking.apm.testcase.dubbo3.services.impl.GreetServiceImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new EmbeddedZooKeeper(2181, false).start();
SpringApplication.run(Application.class, args);
}
@Configuration
public static class DubboConfiguration {
private ApplicationConfig applicationConfig = new ApplicationConfig(Application.class.getSimpleName());
private RegistryConfig registryConfig = new RegistryConfig("zookeeper://127.0.0.1:2181");
private ProtocolConfig protocolConfig = new ProtocolConfig("dubbo", 20080);
public DubboConfiguration() {
ApplicationModel.getConfigManager().setApplication(applicationConfig);
}
@Bean(destroyMethod = "unexport")
public ServiceConfig<GreetService> service() {
ServiceConfig<GreetService> serviceConfig = new ServiceConfig<>();
serviceConfig.setRegistry(registryConfig);
serviceConfig.setProtocol(protocolConfig);
serviceConfig.setInterface(GreetService.class);
serviceConfig.setRef(new GreetServiceImpl());
serviceConfig.setTimeout(5000);
serviceConfig.export();
return serviceConfig;
}
@Bean(destroyMethod = "destroy")
public ReferenceConfig<GreetService> reference() {
ReferenceConfig<GreetService> referenceConfig = new ReferenceConfig<>();
referenceConfig.setRegistry(registryConfig);
referenceConfig.setInterface(GreetService.class);
referenceConfig.setScope("remote");
return referenceConfig;
}
}
}

View File

@ -0,0 +1,265 @@
/*
* 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.
*
*/
/*
* Copyright 2014 the original author or authors.
*
* Licensed 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.testcase.dubbo3;
import org.apache.zookeeper.server.ServerConfig;
import org.apache.zookeeper.server.ZooKeeperServerMain;
import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.SmartLifecycle;
import org.springframework.util.ErrorHandler;
import org.springframework.util.SocketUtils;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.UUID;
/**
* from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java
* <p>
* Helper class to start an embedded instance of standalone (non clustered) ZooKeeper.
* <p>
* NOTE: at least an external standalone server (if not an ensemble) are recommended, even for {@link
* org.springframework.xd.dirt.server.singlenode.SingleNodeApplication}
*/
public class EmbeddedZooKeeper implements SmartLifecycle {
/**
* Logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(EmbeddedZooKeeper.class);
/**
* ZooKeeper client port. This will be determined dynamically upon startup.
*/
private final int clientPort;
/**
* Whether to auto-start. Default is true.
*/
private boolean autoStartup = true;
/**
* Lifecycle phase. Default is 0.
*/
private int phase = 0;
/**
* Thread for running the ZooKeeper server.
*/
private volatile Thread zkServerThread;
/**
* ZooKeeper server.
*/
private volatile ZooKeeperServerMain zkServer;
/**
* {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread.
*/
private ErrorHandler errorHandler;
private boolean daemon = true;
/**
* Construct an EmbeddedZooKeeper with a random port.
*/
public EmbeddedZooKeeper() {
clientPort = SocketUtils.findAvailableTcpPort();
}
/**
* Construct an EmbeddedZooKeeper with the provided port.
*
* @param clientPort port for ZooKeeper server to bind to
*/
public EmbeddedZooKeeper(int clientPort, boolean daemon) {
this.clientPort = clientPort;
this.daemon = daemon;
}
/**
* Returns the port that clients should use to connect to this embedded server.
*
* @return dynamically determined client port
*/
public int getClientPort() {
return this.clientPort;
}
/**
* Specify whether to start automatically. Default is true.
*
* @param autoStartup whether to start automatically
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isAutoStartup() {
return this.autoStartup;
}
/**
* Specify the lifecycle phase for the embedded server.
*
* @param phase the lifecycle phase
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* {@inheritDoc}
*/
@Override
public int getPhase() {
return this.phase;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRunning() {
return zkServerThread != null;
}
/**
* Start the ZooKeeper server in a background thread.
* <p>
* Register an error handler via {@link #setErrorHandler} in order to handle any exceptions thrown during startup or
* execution.
*/
@Override
public synchronized void start() {
if (zkServerThread == null) {
zkServerThread = new Thread(new ServerRunnable(), "ZooKeeper Server Starter");
zkServerThread.setDaemon(daemon);
zkServerThread.start();
}
}
/**
* Shutdown the ZooKeeper server.
*/
@Override
public synchronized void stop() {
if (zkServerThread != null) {
// The shutdown method is protected...thus this hack to invoke it.
// This will log an exception on shutdown; see
// https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.
try {
Method shutdown = ZooKeeperServerMain.class.getDeclaredMethod("shutdown");
shutdown.setAccessible(true);
shutdown.invoke(zkServer);
} catch (Exception e) {
throw new RuntimeException(e);
}
// It is expected that the thread will exit after
// the server is shutdown; this will block until
// the shutdown is complete.
try {
zkServerThread.join(5000);
zkServerThread = null;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOGGER.warn("Interrupted while waiting for embedded ZooKeeper to exit");
// abandoning zk thread
zkServerThread = null;
}
}
}
/**
* Stop the server if running and invoke the callback when complete.
*/
@Override
public void stop(Runnable callback) {
stop();
callback.run();
}
/**
* Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none
* is provided, only error-level logging will occur.
*
* @param errorHandler the {@link ErrorHandler} to be invoked
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Runnable implementation that starts the ZooKeeper server.
*/
private class ServerRunnable implements Runnable {
@Override
public void run() {
try {
Properties properties = new Properties();
File file = new File(System.getProperty("java.io.tmpdir")
+ File.separator + UUID.randomUUID());
file.deleteOnExit();
properties.setProperty("dataDir", file.getAbsolutePath());
properties.setProperty("clientPort", String.valueOf(clientPort));
QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
quorumPeerConfig.parseProperties(properties);
zkServer = new ZooKeeperServerMain();
ServerConfig configuration = new ServerConfig();
configuration.readFrom(quorumPeerConfig);
zkServer.runFromConfig(configuration);
} catch (Exception e) {
if (errorHandler != null) {
errorHandler.handleError(e);
} else {
LOGGER.error("Exception running embedded ZooKeeper", e);
}
}
}
}
}

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.testcase.dubbo3.controller;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.skywalking.apm.testcase.dubbo3.services.GreetService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/case")
public class CaseController {
private static final String SUCCESS = "Success";
@Autowired
private ReferenceConfig<GreetService> referenceConfig;
@RequestMapping("/healthCheck")
@ResponseBody
public String healthCheck() {
return SUCCESS;
}
@RequestMapping("/dubbo")
@ResponseBody
public String dubbo() {
GreetService greetService = referenceConfig.get();
greetService.doBusiness("helloWorld");
return SUCCESS;
}
}

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.
*
*/
package org.apache.skywalking.apm.testcase.dubbo3.services;
public interface GreetService {
String doBusiness(String s);
}

View File

@ -0,0 +1,29 @@
/*
* 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.testcase.dubbo3.services.impl;
import org.apache.skywalking.apm.testcase.dubbo3.services.GreetService;
public class GreetServiceImpl implements GreetService {
@Override
public String doBusiness(String s) {
return "{name:'" + s + "'}";
}
}

View File

@ -0,0 +1,21 @@
# 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: /dubbo-3.x-scenario

View File

@ -0,0 +1,17 @@
# 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.
3.0.4