spring annotation enhance (#5320)
This commit is contained in:
parent
f731c25856
commit
a6e45d04c9
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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 {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 {
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue