未验证 提交 a6e45d04 编写于 作者: E Evan 提交者: GitHub

spring annotation enhance (#5320)

上级 f731c258
......@@ -72,7 +72,7 @@ public class ClassAnnotationMatch implements IndirectMatch {
return isAnnotatedWith(named(annotationName));
}
public static ClassMatch byClassAnnotationMatch(String[] annotations) {
public static ClassAnnotationMatch byClassAnnotationMatch(String... annotations) {
return new ClassAnnotationMatch(annotations);
}
}
/*
* 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.match;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import static net.bytebuddy.matcher.ElementMatchers.nameMatches;
/**
* Match the class by given class name regex expression.
*/
public class RegexMatch implements IndirectMatch {
private String[] regexExpressions;
private RegexMatch(String... regexExpressions) {
if (regexExpressions == null || regexExpressions.length == 0) {
throw new IllegalArgumentException("annotations is null");
}
this.regexExpressions = regexExpressions;
}
@Override
public ElementMatcher.Junction buildJunction() {
ElementMatcher.Junction regexJunction = null;
for (String regexExpression : regexExpressions) {
if (regexJunction == null) {
regexJunction = nameMatches(regexExpression);
} else {
regexJunction = regexJunction.or(nameMatches(regexExpression));
}
}
return regexJunction;
}
@Override
public boolean isMatch(TypeDescription typeDescription) {
boolean isMatch = false;
for (String matchExpression : regexExpressions) {
isMatch = typeDescription.getTypeName().matches(matchExpression);
if (isMatch) {
break;
}
}
return isMatch;
}
public static RegexMatch byRegexMatch(String... regexExpressions) {
return new RegexMatch(regexExpressions);
}
}
\ No newline at end of file
/*
* 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.match;
import net.bytebuddy.description.type.TypeDescription;
import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
import org.junit.Assert;
import org.junit.Test;
import static org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.byClassAnnotationMatch;
import static org.apache.skywalking.apm.agent.core.plugin.match.RegexMatch.byRegexMatch;
public class MatchTest {
private static final String[] REGEX = new String[] {
".*Service.*",
".*Repository.*"
};
@Test
public void testRegexMatch() {
RegexMatch regexMatch = byRegexMatch(REGEX);
TypeDescription typeDefinition = TypeDescription.ForLoadedType.of(TestService.class);
Assert.assertTrue(regexMatch.isMatch(typeDefinition));
typeDefinition = TypeDescription.ForLoadedType.of(TestDao.class);
Assert.assertFalse(regexMatch.isMatch(typeDefinition));
typeDefinition = TypeDescription.ForLoadedType.of(TestRepository.class);
Assert.assertTrue(regexMatch.isMatch(typeDefinition));
}
@Test
public void testAnnotationMatch() {
ClassAnnotationMatch classAnnotationMatch = byClassAnnotationMatch(MatchTestAnnotation.class.getName());
TypeDescription typeDefinition = TypeDescription.ForLoadedType.of(TestService.class);
Assert.assertFalse(classAnnotationMatch.isMatch(typeDefinition));
typeDefinition = TypeDescription.ForLoadedType.of(TestDao.class);
Assert.assertTrue(classAnnotationMatch.isMatch(typeDefinition));
typeDefinition = TypeDescription.ForLoadedType.of(TestRepository.class);
Assert.assertTrue(classAnnotationMatch.isMatch(typeDefinition));
}
@Test
public void testLogicalMatchOperation() {
IndirectMatch match = LogicalMatchOperation.and(
byRegexMatch(REGEX),
byClassAnnotationMatch(MatchTestAnnotation.class.getName())
);
TypeDescription typeDefinition = TypeDescription.ForLoadedType.of(TestService.class);
Assert.assertFalse(match.isMatch(typeDefinition));
typeDefinition = TypeDescription.ForLoadedType.of(TestDao.class);
Assert.assertFalse(match.isMatch(typeDefinition));
typeDefinition = TypeDescription.ForLoadedType.of(TestRepository.class);
Assert.assertTrue(match.isMatch(typeDefinition));
}
public static class TestService {
}
@MatchTestAnnotation
public static class TestDao {
}
@MatchTestAnnotation
public static class TestRepository {
}
}
\ No newline at end of file
/*
* 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.match;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MatchTestAnnotation {
}
\ No newline at end of file
......@@ -93,3 +93,6 @@ logging.level=${SW_LOGGING_LEVEL:INFO}
# Exclude activated plugins
# plugin.exclude_plugins=${SW_EXCLUDE_PLUGINS:""}
# Match spring bean with regex expression for classname
# plugin.springannotation.classname_match_regex_expression=${SW_SPRINGANNOTATION_CLASSNAME_MATCH_REGEX_EXPRESSION:""}
......@@ -24,11 +24,17 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterc
import org.apache.skywalking.apm.agent.core.plugin.interceptor.DeclaredInstanceMethodsInterceptPoint;
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.logical.LogicalMatchOperation;
import org.apache.skywalking.apm.util.StringUtil;
import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.byClassAnnotationMatch;
import static org.apache.skywalking.apm.agent.core.plugin.match.RegexMatch.byRegexMatch;
import static org.apache.skywalking.apm.plugin.spring.annotations.SpringAnnotationConfig.Plugin.SpringAnnotation.CLASSNAME_MATCH_REGEX_EXPRESSION;
public abstract class AbstractSpringBeanInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.spring.annotations.SpringAnnotationInterceptor";
......@@ -46,8 +52,9 @@ public abstract class AbstractSpringBeanInstrumentation extends ClassInstanceMet
new DeclaredInstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return isPublic().and(not(isDeclaredBy(Object.class)).and(not(named(INTERCEPT_GET_SKYWALKING_DYNAMIC_FIELD_METHOD)))
.and(not(named(INTERCEPT_SET_SKYWALKING_DYNAMIC_FIELD_METHOD))));
return isPublic().and(not(isDeclaredBy(Object.class))
.and(not(named(INTERCEPT_GET_SKYWALKING_DYNAMIC_FIELD_METHOD)))
.and(not(named(INTERCEPT_SET_SKYWALKING_DYNAMIC_FIELD_METHOD))));
}
@Override
......@@ -62,4 +69,19 @@ public abstract class AbstractSpringBeanInstrumentation extends ClassInstanceMet
}
};
}
@Override
protected ClassMatch enhanceClass() {
if (StringUtil.isEmpty(CLASSNAME_MATCH_REGEX_EXPRESSION)) {
return byClassAnnotationMatch(getEnhanceAnnotation());
} else {
return LogicalMatchOperation.and(
byRegexMatch(CLASSNAME_MATCH_REGEX_EXPRESSION.split(",")),
byClassAnnotationMatch(getEnhanceAnnotation())
);
}
}
protected abstract String getEnhanceAnnotation();
}
/*
* 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.spring.annotations;
import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
public class SpringAnnotationConfig {
public static class Plugin {
@PluginConfig(root = SpringAnnotationConfig.class)
public static class SpringAnnotation {
/**
* regex expression to match spring bean classname
*/
public static String CLASSNAME_MATCH_REGEX_EXPRESSION = "";
}
}
}
\ No newline at end of file
......@@ -18,17 +18,14 @@
package org.apache.skywalking.apm.plugin.spring.annotations.bean;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.plugin.spring.annotations.AbstractSpringBeanInstrumentation;
import static org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.byClassAnnotationMatch;
public class SpringBeanInstrumentation extends AbstractSpringBeanInstrumentation {
public static final String ENHANCE_ANNOTATION = "org.springframework.context.annotation.Bean";
@Override
protected ClassMatch enhanceClass() {
return byClassAnnotationMatch(new String[] {ENHANCE_ANNOTATION});
protected String getEnhanceAnnotation() {
return ENHANCE_ANNOTATION;
}
}
......@@ -18,17 +18,14 @@
package org.apache.skywalking.apm.plugin.spring.annotations.component;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.plugin.spring.annotations.AbstractSpringBeanInstrumentation;
import static org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.byClassAnnotationMatch;
public class SpringComponentInstrumentation extends AbstractSpringBeanInstrumentation {
public static final String ENHANCE_ANNOTATION = "org.springframework.stereotype.Component";
@Override
protected ClassMatch enhanceClass() {
return byClassAnnotationMatch(new String[] {ENHANCE_ANNOTATION});
protected String getEnhanceAnnotation() {
return ENHANCE_ANNOTATION;
}
}
......@@ -18,17 +18,14 @@
package org.apache.skywalking.apm.plugin.spring.annotations.repository;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.plugin.spring.annotations.AbstractSpringBeanInstrumentation;
import static org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.byClassAnnotationMatch;
public class SpringRepositoryInstrumentation extends AbstractSpringBeanInstrumentation {
public static final String ENHANCE_ANNOTATION = "org.springframework.stereotype.Repository";
@Override
protected ClassMatch enhanceClass() {
return byClassAnnotationMatch(new String[] {ENHANCE_ANNOTATION});
protected String getEnhanceAnnotation() {
return ENHANCE_ANNOTATION;
}
}
......@@ -18,17 +18,14 @@
package org.apache.skywalking.apm.plugin.spring.annotations.services;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.plugin.spring.annotations.AbstractSpringBeanInstrumentation;
import static org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.byClassAnnotationMatch;
public class SpringServicesInstrumentation extends AbstractSpringBeanInstrumentation {
public static final String ENHANCE_ANNOTATION = "org.springframework.stereotype.Service";
@Override
protected ClassMatch enhanceClass() {
return byClassAnnotationMatch(new String[] {ENHANCE_ANNOTATION});
protected String getEnhanceAnnotation() {
return ENHANCE_ANNOTATION;
}
}
......@@ -112,7 +112,6 @@ property key | Description | Default |
`meter.max_meter_size`| Max size of the meter pool |`500`|
`plugin.peer_max_length `|Peer maximum description limit.|`200`|
`plugin.exclude_plugins `|Exclude some plugins define in plugins dir.Plugin names is defined in [Agent plugin list](Plugin-list.md)|`""`|
`plugin.mongodb.trace_param`|If true, trace all the parameters in MongoDB access, default is false. Only trace the operation, not include parameters.|`false`|
`plugin.mongodb.filter_length_limit`|If set to positive number, the `WriteRequest.params` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem.|`256`|
`plugin.elasticsearch.trace_dsl`|If true, trace all the DSL(Domain Specific Language) in ElasticSearch access, default is false.|`false`|
......@@ -151,6 +150,8 @@ property key | Description | Default |
`plugin.kafka.topic_segment` | Specify which Kafka topic name for traces data to report to. | `skywalking_segments` |
`plugin.kafka.topic_profilings` | Specify which Kafka topic name for Thread Profiling snapshot to report to. | `skywalking_profilings` |
`plugin.kafka.topic_management` | Specify which Kafka topic name for the register or heartbeat data of Service Instance to report to. | `skywalking_managements` |
`plugin.springannotation.classname_match_regex_expression` | Match spring beans with regex expression for the class name. Multiple expressions could be separated by a comma. This only works when `Spring annotation plugin` has been activated. | `All the spring beans tagged with @Bean,@Service,@Dao, or @Repository.` |
## Optional Plugins
Java agent plugins are all pluggable. Optional plugins could be provided in `optional-plugins` folder under agent or 3rd party repositories.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册