未验证 提交 e0a4c440 编写于 作者: L libinglong 提交者: GitHub
上级 4acbca00
......@@ -23,6 +23,7 @@ Release Notes.
* Fix DataCarrier's `org.apache.skywalking.apm.commons.datacarrier.buffer.Buffer` implementation isn't activated in `IF_POSSIBLE` mode.
* Fix ArrayBlockingQueueBuffer's useless `IF_POSSIBLE` mode list
* Support building gRPC TLS channel but CA file is not required.
* Add witness method mechanism in the agent plugin core.
* Add Dolphinscheduler plugin definition.
* Make sampling still works when the trace ignores plug-in activation.
* Fix mssql-plugin occur ClassCastException when call the method of return generate key.
......
......@@ -27,8 +27,11 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsIn
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
import org.apache.skywalking.apm.util.StringUtil;
import java.util.List;
/**
* Basic abstract class of all sky-walking auto-instrumentation plugins.
* <p>
......@@ -57,19 +60,28 @@ public abstract class AbstractClassEnhancePluginDefine {
}
LOGGER.debug("prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName);
WitnessFinder finder = WitnessFinder.INSTANCE;
/**
* find witness classes for enhance class
*/
String[] witnessClasses = witnessClasses();
if (witnessClasses != null) {
for (String witnessClass : witnessClasses) {
if (!WitnessClassFinder.INSTANCE.exist(witnessClass, classLoader)) {
if (!finder.exist(witnessClass, classLoader)) {
LOGGER.warn("enhance class {} by plugin {} is not working. Because witness class {} is not existed.", transformClassName, interceptorDefineClassName, witnessClass);
return null;
}
}
}
List<WitnessMethod> witnessMethods = witnessMethods();
if (!CollectionUtil.isEmpty(witnessMethods)) {
for (WitnessMethod witnessMethod : witnessMethods) {
if (!finder.exist(witnessMethod, classLoader)) {
LOGGER.warn("enhance class {} by plugin {} is not working. Because witness method {} is not existed.", transformClassName, interceptorDefineClassName, witnessMethod);
return null;
}
}
}
/**
* find origin class source code for interceptor
......@@ -104,6 +116,10 @@ public abstract class AbstractClassEnhancePluginDefine {
return new String[] {};
}
protected List<WitnessMethod> witnessMethods() {
return null;
}
public boolean isBootstrapInstrumentation() {
return false;
}
......
......@@ -18,24 +18,36 @@
package org.apache.skywalking.apm.agent.core.plugin;
import net.bytebuddy.pool.TypePool;
import java.util.HashMap;
import java.util.Map;
import net.bytebuddy.pool.TypePool;
/**
* The <code>WitnessClassFinder</code> represents a pool of {@link TypePool}s, each {@link TypePool} matches a {@link
* ClassLoader}, which helps to find the class define existed or not.
* The <code>WitnessFinder</code> represents a pool of {@link TypePool}s, each {@link TypePool} matches a {@link
* ClassLoader}, which helps to find the class declaration existed or not.
*/
public enum WitnessClassFinder {
public enum WitnessFinder {
INSTANCE;
private Map<ClassLoader, TypePool> poolMap = new HashMap<ClassLoader, TypePool>();
private final Map<ClassLoader, TypePool> poolMap = new HashMap<ClassLoader, TypePool>();
/**
* @param classLoader for finding the witnessClass
* @return true, if the given witnessClass exists, through the given classLoader.
*/
public boolean exist(String witnessClass, ClassLoader classLoader) {
return getResolution(witnessClass, classLoader)
.isResolved();
}
/**
* get TypePool.Resolution of the witness class
* @param witnessClass class name
* @param classLoader classLoader for finding the witnessClass
* @return TypePool.Resolution
*/
private TypePool.Resolution getResolution(String witnessClass, ClassLoader classLoader) {
ClassLoader mappingKey = classLoader == null ? NullClassLoader.INSTANCE : classLoader;
if (!poolMap.containsKey(mappingKey)) {
synchronized (poolMap) {
......@@ -46,9 +58,24 @@ public enum WitnessClassFinder {
}
}
TypePool typePool = poolMap.get(mappingKey);
TypePool.Resolution witnessClassResolution = typePool.describe(witnessClass);
return witnessClassResolution.isResolved();
return typePool.describe(witnessClass);
}
/**
* @param classLoader for finding the witness method
* @return true, if the given witness method exists, through the given classLoader.
*/
public boolean exist(WitnessMethod witnessMethod, ClassLoader classLoader) {
TypePool.Resolution resolution = getResolution(witnessMethod.getDeclaringClassName(), classLoader);
if (!resolution.isResolved()) {
return false;
}
return !resolution.resolve()
.getDeclaredMethods()
.filter(witnessMethod.getElementMatcher())
.isEmpty();
}
}
final class NullClassLoader extends ClassLoader {
......
/*
* 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.agent.core.plugin;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
/**
* Witness Method for plugin activation
*/
@ToString
@RequiredArgsConstructor
public class WitnessMethod {
/**
* the class or interface name where the witness method is declared.
*/
@Getter
private final String declaringClassName;
/**
* matcher to match the witness method
*/
@Getter
private final ElementMatcher<? super MethodDescription.InDefinedShape> elementMatcher;
}
/*
* 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.agent.core.plugin.witness;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import org.apache.skywalking.apm.agent.core.plugin.WitnessFinder;
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
import java.util.Map;
/**
* unit test for WitnessFinder
*/
public class WitnessTest {
private final String className = "org.apache.skywalking.apm.agent.core.plugin.witness.WitnessTest";
private final WitnessFinder finder = WitnessFinder.INSTANCE;
@Test
public void testWitnessClass() {
Assert.assertTrue(finder.exist(className, this.getClass().getClassLoader()));
}
@Test
public void testWitnessMethod() {
ElementMatcher.Junction<MethodDescription> junction = ElementMatchers.named("foo")
.and(ElementMatchers.returnsGeneric(target -> "java.util.List<java.util.Map<java.lang.String, java.lang.Object>>".equals(target.getTypeName())))
.and(ElementMatchers.takesGenericArgument(0, target -> "java.util.List<java.util.Map<java.lang.String, java.lang.Object>>".equals(target.getTypeName())))
.and(ElementMatchers.takesArgument(1, target -> "java.lang.String".equals(target.getName())));
WitnessMethod witnessMethod = new WitnessMethod(className, junction);
Assert.assertTrue(finder.exist(witnessMethod, this.getClass().getClassLoader()));
}
@Test
public void testWitnessMethodOnlyUsingName() {
ElementMatcher.Junction<MethodDescription> junction = ElementMatchers.named("foo");
WitnessMethod witnessMethod = new WitnessMethod(className, junction);
Assert.assertTrue(finder.exist(witnessMethod, this.getClass().getClassLoader()));
}
public List<Map<String, Object>> foo(List<Map<String, Object>> param, String s) {
return null;
}
}
......@@ -299,6 +299,31 @@ The following sections will tell you how to implement the interceptor.
tomcat-7.x/8.x=TomcatInstrumentation
```
4. Set up `witnessClasses` and/or `witnessMethods` if the instrumentation should be activated in specific versions.
Example:
```java
// The plugin is activated only when the foo.Bar class exists.
@Override
protected String[] witnessClasses() {
return new String[] {
"foo.Bar"
};
}
// The plugin is activated only when the foo.Bar#hello method exists.
@Override
protected List<WitnessMethod> witnessMethods() {
List<WitnessMethod> witnessMethodList = new ArrayList<>();
WitnessMethod witnessMethod = new WitnessMethod("foo.Bar", ElementMatchers.named("hello"));
witnessMethodList.add(witnessMethod);
return witnessMethodList;
}
```
For more example, see [WitnessTest.java](/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/plugin/witness/WitnessTest.java)
### Implement an interceptor
As an interceptor for an instance method, the interceptor implements
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册