diff --git a/Jenkinsfile-Agent-Test b/Jenkinsfile-Agent-Test
index b4412b16b..8cc864cd6 100755
--- a/Jenkinsfile-Agent-Test
+++ b/Jenkinsfile-Agent-Test
@@ -60,6 +60,12 @@ pipeline {
sh 'bash test/plugin/run.sh --build_id=${BUILD_ID} httpclient-4.3.x-scenario'
}
}
+
+ stage('ehcache 2.8.x-2.10.x') {
+ steps {
+ sh 'bash test/plugin/run.sh --build_id=${BUILD_ID} ehcache-2.x-scenario'
+ }
+ }
}
post {
diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
index 7bb53c80a..45c494ad0 100755
--- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -139,4 +139,6 @@ public class ComponentsDefine {
public static final OfficialComponent PULSAR_PRODUCER = new OfficialComponent(73, "pulsar-producer");
public static final OfficialComponent PULSAR_CONSUMER = new OfficialComponent(74, "pulsar-consumer");
+
+ public static final OfficialComponent EHCACHE = new OfficialComponent(75, "Ehcache");
}
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/pom.xml
new file mode 100644
index 000000000..4c0d0ea38
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/pom.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+ apm-sdk-plugin
+ org.apache.skywalking
+ 6.5.0-SNAPSHOT
+
+ 4.0.0
+
+ apm-ehcache-2.x-plugin
+ ehcache-2.x-plugin
+ jar
+
+
+ UTF-8
+ 2.10.2.2.21
+
+
+
+
+
+ net.sf.ehcache
+ ehcache
+ ${ehcache-client.version}
+ provided
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheConstructorInterceptor.java
new file mode 100644
index 000000000..718d90155
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheConstructorInterceptor.java
@@ -0,0 +1,38 @@
+/*
+ * 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.ehcache.v2;
+
+import net.sf.ehcache.config.CacheConfiguration;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+
+/**
+ * @author MrPro
+ */
+public class EhcacheConstructorInterceptor implements InstanceConstructorInterceptor {
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ CacheConfiguration cacheConfiguration = (CacheConfiguration) allArguments[0];
+
+ // get cache name
+ if (cacheConfiguration != null) {
+ objInst.setSkyWalkingDynamicField(new EhcacheEnhanceInfo(cacheConfiguration.getName()));
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheEnhanceInfo.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheEnhanceInfo.java
new file mode 100644
index 000000000..b61caef2c
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheEnhanceInfo.java
@@ -0,0 +1,42 @@
+/*
+ * 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.ehcache.v2;
+
+/**
+ * @author MrPro
+ */
+public class EhcacheEnhanceInfo {
+
+ private String cacheName;
+
+ public EhcacheEnhanceInfo() {
+ }
+
+ public EhcacheEnhanceInfo(String cacheName) {
+ this.cacheName = cacheName;
+ }
+
+ public String getCacheName() {
+ return cacheName;
+ }
+
+ public void setCacheName(String cacheName) {
+ this.cacheName = cacheName;
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheLockInterceptor.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheLockInterceptor.java
new file mode 100644
index 000000000..73be48195
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheLockInterceptor.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.ehcache.v2;
+
+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 java.lang.reflect.Method;
+
+import static org.apache.skywalking.apm.plugin.ehcache.v2.define.EhcachePluginInstrumentation.LOCK_ENHANCE_METHOD_SUFFIX;
+
+/**
+ * @author MrPro
+ */
+public class EhcacheLockInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ EhcacheEnhanceInfo enhanceInfo = (EhcacheEnhanceInfo) objInst.getSkyWalkingDynamicField();
+
+ String operateName = method.getName().substring(0, method.getName().length() - LOCK_ENHANCE_METHOD_SUFFIX.length());
+
+ AbstractSpan span = ContextManager.createLocalSpan("Ehcache/" + operateName + "/" + enhanceInfo.getCacheName());
+ span.setComponent(ComponentsDefine.EHCACHE);
+ SpanLayer.asCache(span);
+
+ Object element = allArguments[0];
+ if (element != null) {
+ Tags.DB_STATEMENT.set(span, element.toString());
+ }
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheOperateAllInterceptor.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheOperateAllInterceptor.java
new file mode 100644
index 000000000..eb478e42a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheOperateAllInterceptor.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.ehcache.v2;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+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 java.lang.reflect.Method;
+
+/**
+ * @author MrPro
+ */
+public class EhcacheOperateAllInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ EhcacheEnhanceInfo enhanceInfo = (EhcacheEnhanceInfo) objInst.getSkyWalkingDynamicField();
+
+ AbstractSpan span = ContextManager.createLocalSpan("Ehcache/" + method.getName() + "/" + enhanceInfo.getCacheName());
+ span.setComponent(ComponentsDefine.EHCACHE);
+ SpanLayer.asCache(span);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheOperateElementInterceptor.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheOperateElementInterceptor.java
new file mode 100644
index 000000000..e2ef5e4cd
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheOperateElementInterceptor.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.ehcache.v2;
+
+import net.sf.ehcache.Element;
+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 java.lang.reflect.Method;
+
+/**
+ * @author MrPro
+ */
+public class EhcacheOperateElementInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ EhcacheEnhanceInfo enhanceInfo = (EhcacheEnhanceInfo) objInst.getSkyWalkingDynamicField();
+
+ AbstractSpan span = ContextManager.createLocalSpan("Ehcache/" + method.getName() + "/" + enhanceInfo.getCacheName());
+ span.setComponent(ComponentsDefine.EHCACHE);
+ SpanLayer.asCache(span);
+
+ Element element = (Element) allArguments[0];
+ if (element != null && element.getObjectKey() != null) {
+ Tags.DB_STATEMENT.set(span, element.getObjectKey().toString());
+ }
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheOperateObjectInterceptor.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheOperateObjectInterceptor.java
new file mode 100644
index 000000000..bfbdffa57
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheOperateObjectInterceptor.java
@@ -0,0 +1,61 @@
+/*
+ * 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.ehcache.v2;
+
+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 java.lang.reflect.Method;
+
+/**
+ * @author MrPro
+ */
+public class EhcacheOperateObjectInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ EhcacheEnhanceInfo enhanceInfo = (EhcacheEnhanceInfo) objInst.getSkyWalkingDynamicField();
+
+ AbstractSpan span = ContextManager.createLocalSpan("Ehcache/" + method.getName() + "/" + enhanceInfo.getCacheName());
+ span.setComponent(ComponentsDefine.EHCACHE);
+ SpanLayer.asCache(span);
+
+ Object element = allArguments[0];
+ if (element != null) {
+ Tags.DB_STATEMENT.set(span, element.toString());
+ }
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/define/EhcachePluginInstrumentation.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/define/EhcachePluginInstrumentation.java
new file mode 100644
index 000000000..fb3baaf73
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/define/EhcachePluginInstrumentation.java
@@ -0,0 +1,185 @@
+/*
+ * 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.ehcache.v2.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.*;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ *
+ * {@link EhcachePluginInstrumentation} enhance @{@link net.sf.ehcache.Cache}
+ *
+ * @author MrPro
+ */
+public class EhcachePluginInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ public static final String INTERCEPT_CLASS = "net.sf.ehcache.Cache";
+ public static final String CONSTRUCTOR_CLASS_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.ehcache.v2.EhcacheConstructorInterceptor";
+
+ // get and put value
+ public static final String PUT_CACHE_ENHANCE_METHOD = "put";
+ public static final String GET_CACHE_ENHANCE_METHOD = "get";
+ public static final String GET_QUIET_CACHE_ENHANCE_METHOD = "getQuiet";
+ public static final String REMOVE_CACHE_ENHANCE_METHOD = "remove";
+ public static final String REMOVE_AND_RETURN_ELEMENT_CACHE_ENHANCE_METHOD = "removeAndReturnElement";
+ public static final String REPLACE_CACHE_ENHANCE_METHOD = "replace";
+ public static final String REMOVE_QUIET_CACHE_ENHANCE_METHOD = "removeQuiet";
+ public static final String REMOVE_WITH_WRITE_CACHE_INHANCE_METHOD = "removeWithWriter";
+ public static final String REMOVE_ELEMENT_CACHE_ENHANCE_METHOD = "removeElement";
+ public static final String REMOVE_ALL_CACHE_INHANCE_METHOD = "removeAll";
+ public static final String PUT_ALL_CACHE_ENHANCE_METHOD = "putAll";
+ public static final String PUT_WITH_WRITE_CACHE_ENHANCE_METHOD = "putWithWriter";
+ public static final String PUT_QUITE_CACHE_ENHANCE_METHOD = "putQuiet";
+ public static final String GET_WITH_LOADER_CACHE_ENHANCE_METHOD = "getWithLoader";
+ public static final String PUT_IF_ABSENT_CACHE_ENHANCE_METHOD = "putIfAbsent";
+ public static final String GET_ALL_CACHE_ENHANCE_METHOD = "getAll";
+ public static final String LOAD_ALL_CACHE_ENHANCE_METHOD = "loadAll";
+ public static final String GET_ALL_WITH_LOADER_CACHE_ENHANCE_METHOD = "getAllWithLoader";
+ public static final String OPERATE_ELEMENT_CACHE_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.ehcache.v2.EhcacheOperateElementInterceptor";
+ public static final String OPERATE_OBJECT_CACHE_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.ehcache.v2.EhcacheOperateObjectInterceptor";
+ public static final String OPERATE_ALL_CACHE_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.ehcache.v2.EhcacheOperateAllInterceptor";
+
+
+ // lock and release
+ public static final String LOCK_ENHANCE_METHOD_SUFFIX = "LockOnKey";
+ public static final String WRITE_LOCK_TRY_ENHANCE_METHOD = "tryWrite" + LOCK_ENHANCE_METHOD_SUFFIX;
+ public static final String WRITE_LOCK_RELEASE_ENHANCE_METHOD = "releaseWrite" + LOCK_ENHANCE_METHOD_SUFFIX;
+ public static final String READ_LOCK_TRY_ENHANCE_METHOD = "tryRead" + LOCK_ENHANCE_METHOD_SUFFIX;
+ public static final String READ_LOCK_RELEASE_ENHANCE_METHOD = "releaseRead" + LOCK_ENHANCE_METHOD_SUFFIX;
+ public static final String READ_WRITE_LOCK_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.ehcache.v2.EhcacheLockInterceptor";
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArgument(0, named("net.sf.ehcache.config.CacheConfiguration"));
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return CONSTRUCTOR_CLASS_INTERCEPT_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(GET_WITH_LOADER_CACHE_ENHANCE_METHOD)
+ .or(named(GET_CACHE_ENHANCE_METHOD).and(takesArgument(0, Object.class)))
+ .or(named(GET_QUIET_CACHE_ENHANCE_METHOD).and(takesArgument(0, Object.class)))
+ .or(named(REMOVE_CACHE_ENHANCE_METHOD).and(takesArguments(2)).and(takesArgument(0, Object.class)))
+ .or(named(REMOVE_AND_RETURN_ELEMENT_CACHE_ENHANCE_METHOD))
+ .or(named(REMOVE_QUIET_CACHE_ENHANCE_METHOD))
+ .or(named(REMOVE_WITH_WRITE_CACHE_INHANCE_METHOD));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return OPERATE_OBJECT_CACHE_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(PUT_WITH_WRITE_CACHE_ENHANCE_METHOD)
+ .or(named(PUT_QUITE_CACHE_ENHANCE_METHOD))
+ .or(named(REMOVE_ELEMENT_CACHE_ENHANCE_METHOD))
+ .or(named(REPLACE_CACHE_ENHANCE_METHOD))
+ .or(named(PUT_IF_ABSENT_CACHE_ENHANCE_METHOD).and(takesArguments(2)))
+ .or(named(PUT_CACHE_ENHANCE_METHOD).and(takesArguments(2)));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return OPERATE_ELEMENT_CACHE_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(REMOVE_ALL_CACHE_INHANCE_METHOD).and(takesArguments(1).and(takesArgument(0, Boolean.TYPE)))
+ .or(named(REMOVE_ALL_CACHE_INHANCE_METHOD).and(takesArguments(2)))
+ .or(named(PUT_ALL_CACHE_ENHANCE_METHOD).and(takesArguments(2)))
+ .or(named(GET_ALL_WITH_LOADER_CACHE_ENHANCE_METHOD))
+ .or(named(GET_ALL_CACHE_ENHANCE_METHOD))
+ .or(named(LOAD_ALL_CACHE_ENHANCE_METHOD));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return OPERATE_ALL_CACHE_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(READ_LOCK_RELEASE_ENHANCE_METHOD)
+ .or(named(READ_LOCK_TRY_ENHANCE_METHOD)
+ .or(named(WRITE_LOCK_RELEASE_ENHANCE_METHOD))
+ .or(named(WRITE_LOCK_TRY_ENHANCE_METHOD)));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return READ_WRITE_LOCK_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(INTERCEPT_CLASS);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 000000000..cfbaa196a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/resources/skywalking-plugin.def
@@ -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.
+
+ehcache-2.x=org.apache.skywalking.apm.plugin.ehcache.v2.define.EhcachePluginInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheInterceptorTest.java
new file mode 100644
index 000000000..566261a2d
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheInterceptorTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.ehcache.v2;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+import net.sf.ehcache.config.CacheConfiguration;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+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.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.powermock.reflect.Whitebox;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static org.apache.skywalking.apm.plugin.ehcache.v2.define.EhcachePluginInstrumentation.*;
+import static org.hamcrest.CoreMatchers.is;
+
+/**
+ * @author MrPro
+ */
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+public class EhcacheInterceptorTest {
+
+ private static final String CACHE_NAME = "test";
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+
+ private EhcacheOperateObjectInterceptor operateObjectInterceptor;
+ private EhcacheOperateElementInterceptor operateElementInterceptor;
+ private EhcacheOperateAllInterceptor operateAllInterceptor;
+ private EhcacheLockInterceptor lockInterceptor;
+ private EhcacheConstructorInterceptor constructorInterceptor;
+ private Object[] operateObjectArguments;
+ private Object[] operateElementArguments;
+ private Object[] tryLockArguments;
+ private Object[] releaseLockArguments;
+
+ private Exception exception;
+
+ private Method putCacheMethod;
+ private Method getCacheMethod;
+ private Method getAllMethod;
+
+ private Method tryReadLockMethod;
+ private Method tryWriteLockMethod;
+ private Method releaseReadLockMethod;
+ private Method releaseWriteLockMethod;
+
+ private EnhancedInstance enhancedInstance = new EnhancedInstance() {
+ @Override
+ public Object getSkyWalkingDynamicField() {
+ return new EhcacheEnhanceInfo(CACHE_NAME);
+ }
+
+ @Override
+ public void setSkyWalkingDynamicField(Object value) {
+ }
+ };
+
+ @Before
+ public void setUp() throws NoSuchMethodException {
+ operateObjectInterceptor = new EhcacheOperateObjectInterceptor();
+ operateElementInterceptor = new EhcacheOperateElementInterceptor();
+ operateAllInterceptor = new EhcacheOperateAllInterceptor();
+ constructorInterceptor = new EhcacheConstructorInterceptor();
+ lockInterceptor = new EhcacheLockInterceptor();
+
+ exception = new Exception();
+
+ operateObjectArguments = new Object[] {"dataKey"};
+ operateElementArguments = new Element[] {new Element("dataKey", 1)};
+ tryLockArguments = new Object[] {"dataKey", 3000};
+ releaseLockArguments = new Object[] {"dataKey"};
+
+ putCacheMethod = Whitebox.getMethods(Cache.class, PUT_CACHE_ENHANCE_METHOD)[0];
+ getCacheMethod = Whitebox.getMethods(Cache.class, GET_CACHE_ENHANCE_METHOD)[0];
+ getAllMethod = Whitebox.getMethods(Cache.class, GET_ALL_CACHE_ENHANCE_METHOD)[0];
+
+ tryReadLockMethod = Whitebox.getMethods(Cache.class, READ_LOCK_TRY_ENHANCE_METHOD)[0];
+ tryWriteLockMethod = Whitebox.getMethods(Cache.class, WRITE_LOCK_TRY_ENHANCE_METHOD)[0];
+ releaseReadLockMethod = Whitebox.getMethods(Cache.class, READ_LOCK_RELEASE_ENHANCE_METHOD)[0];
+ releaseWriteLockMethod = Whitebox.getMethods(Cache.class, WRITE_LOCK_RELEASE_ENHANCE_METHOD)[0];
+ }
+
+ @Test
+ public void assertConstruct() throws Throwable {
+ constructorInterceptor.onConstruct(enhancedInstance, new Object[] {new CacheConfiguration(CACHE_NAME, 20)});
+ }
+
+ @Test
+ public void assertPutSuccess() throws Throwable {
+ // put arguments
+ operateElementInterceptor.beforeMethod(enhancedInstance, putCacheMethod, operateElementArguments, null, null);
+ operateElementInterceptor.handleMethodException(enhancedInstance, putCacheMethod, null, null, exception);
+ operateElementInterceptor.afterMethod(enhancedInstance, putCacheMethod, operateElementArguments, null, null);
+
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+
+ @Test
+ public void assertGetSuccess() throws Throwable {
+ operateObjectInterceptor.beforeMethod(enhancedInstance, getCacheMethod, operateObjectArguments, null, null);
+ operateObjectInterceptor.handleMethodException(enhancedInstance, getCacheMethod, null, null, exception);
+ operateObjectInterceptor.afterMethod(enhancedInstance, getCacheMethod, operateObjectArguments, null, null);
+
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+
+ @Test
+ public void assertGetAllSuccess() throws Throwable {
+ operateAllInterceptor.beforeMethod(enhancedInstance, getAllMethod, null, null, null);
+ operateAllInterceptor.handleMethodException(enhancedInstance, getAllMethod, null, null, exception);
+ operateAllInterceptor.afterMethod(enhancedInstance, getAllMethod, null, null, null);
+
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(1));
+ }
+
+
+ @Test
+ public void assertLockSuccess() throws Throwable {
+ lockInterceptor.beforeMethod(enhancedInstance, tryReadLockMethod, tryLockArguments, null, null);
+ lockInterceptor.handleMethodException(enhancedInstance, tryReadLockMethod, null, null, exception);
+ lockInterceptor.afterMethod(enhancedInstance, tryReadLockMethod, tryLockArguments, null, null);
+
+ lockInterceptor.beforeMethod(enhancedInstance, tryWriteLockMethod, tryLockArguments, null, null);
+ lockInterceptor.afterMethod(enhancedInstance, tryWriteLockMethod, tryLockArguments, null, null);
+
+ lockInterceptor.beforeMethod(enhancedInstance, releaseReadLockMethod, releaseLockArguments, null, null);
+ lockInterceptor.afterMethod(enhancedInstance, releaseReadLockMethod, releaseLockArguments, null, null);
+
+ lockInterceptor.beforeMethod(enhancedInstance, releaseWriteLockMethod, releaseLockArguments, null, null);
+ lockInterceptor.afterMethod(enhancedInstance, releaseWriteLockMethod, releaseLockArguments, null, null);
+
+ List traceSegments = segmentStorage.getTraceSegments();
+ Assert.assertThat(traceSegments.size(), is(4));
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index d38c4bc97..e7c75eaa8 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -76,6 +76,7 @@
solrj-7.x-plugincassandra-java-driver-3.x-pluginlight4j-plugins
+ ehcache-2.x-pluginpulsar-pluginpom
diff --git a/docs/en/setup/service-agent/java-agent/Supported-list.md b/docs/en/setup/service-agent/java-agent/Supported-list.md
index 07db4d841..9faff5500 100644
--- a/docs/en/setup/service-agent/java-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/java-agent/Supported-list.md
@@ -80,6 +80,8 @@
* Vert.x Web 3.x
* Thread Schedule Framework
* [Spring @Async](https://github.com/spring-projects/spring-framework) 4.x and 5.x
+* Cache
+ * [Ehcache](https://www.ehcache.org/) 2.x
¹Due to license incompatibilities/restrictions these plugins are hosted and released in 3rd part repository,
diff --git a/oap-server/server-core/src/test/resources/component-libraries.yml b/oap-server/server-core/src/test/resources/component-libraries.yml
index bdcf6c2c9..5a57c5fcb 100755
--- a/oap-server/server-core/src/test/resources/component-libraries.yml
+++ b/oap-server/server-core/src/test/resources/component-libraries.yml
@@ -224,6 +224,9 @@ Cassandra:
Light4J:
id: 71
languages: Java
+Ehcache:
+ id: 75
+ languages: Java
# .NET/.NET Core components
# [3000, 4000) for C#/.NET only
diff --git a/oap-server/server-starter/src/main/resources/component-libraries.yml b/oap-server/server-starter/src/main/resources/component-libraries.yml
index 778ebd145..45d0ea806 100755
--- a/oap-server/server-starter/src/main/resources/component-libraries.yml
+++ b/oap-server/server-starter/src/main/resources/component-libraries.yml
@@ -251,6 +251,9 @@ pulsar-producer:
pulsar-consumer:
id: 74
languages: Java
+Ehcache:
+ id: 75
+ languages: Java
# .NET/.NET Core components
# [3000, 4000) for C#/.NET only
diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/ehcache-2.x-scenario/config/expectedData.yaml
new file mode 100644
index 000000000..0562b9ab7
--- /dev/null
+++ b/test/plugin/scenarios/ehcache-2.x-scenario/config/expectedData.yaml
@@ -0,0 +1,136 @@
+# 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.
+registryItems:
+ applications:
+ - {ehcache-2.x-scenario: 2}
+ instances:
+ - {ehcache-2.x-scenario: 1}
+ operationNames:
+ - ehcache-2.x-scenario: [/ehcache-2.x-scenario/case/ehcache, /ehcache-2.x-scenario/healthCheck]
+ heartbeat: []
+segmentItems:
+ - applicationCode: ehcache-2.x-scenario
+ segmentSize: 2
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: /ehcache-2.x-scenario/healthCheck
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 1
+ componentName: ''
+ isError: false
+ spanType: Entry
+ peer: ''
+ peerId: 0
+ tags:
+ - {key: url, value: 'http://localhost:8080/ehcache-2.x-scenario/healthCheck'}
+ - {key: http.method, value: HEAD}
+ - segmentId: not null
+ spans:
+ - operationName: Ehcache/put/testCache
+ operationId: 0
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Cache
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 75
+ componentName: ''
+ isError: false
+ spanType: Local
+ peer: ''
+ peerId: 0
+ tags:
+ - {key: db.statement, value: dataKey}
+ - operationName: Ehcache/get/testCache
+ operationId: 0
+ parentSpanId: 0
+ spanId: 2
+ spanLayer: Cache
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 75
+ componentName: ''
+ isError: false
+ spanType: Local
+ peer: ''
+ peerId: 0
+ tags:
+ - {key: db.statement, value: dataKey}
+ - operationName: Ehcache/putAll/testCache
+ operationId: 0
+ parentSpanId: 0
+ panId: 3
+ spanLayer: Cache
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 75
+ componentName: ''
+ isError: false
+ spanType: Local
+ peer: ''
+ peerId: 0
+ - operationName: Ehcache/tryRead/testCache
+ operationId: 0
+ parentSpanId: 0
+ spanId: 4
+ spanLayer: Cache
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 75
+ componentName: ''
+ isError: false
+ spanType: Local
+ peer: ''
+ peerId: 0
+ tags:
+ - {key: db.statement, value: dataKey}
+ - operationName: Ehcache/releaseRead/testCache
+ operationId: 0
+ parentSpanId: 0
+ spanId: 5
+ spanLayer: Cache
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 75
+ componentName: ''
+ isError: false
+ spanType: Local
+ peer: ''
+ peerId: 0
+ tags:
+ - {key: db.statement, value: dataKey}
+ - operationName: /ehcache-2.x-scenario/case/ehcache
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 1
+ componentName: ''
+ isError: false
+ spanType: Entry
+ peer: ''
+ peerId: 0
+ tags:
+ - {key: url, value: 'http://localhost:8080/ehcache-2.x-scenario/case/ehcache'}
+ - {key: http.method, value: GET}
\ No newline at end of file
diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/configuration.yml b/test/plugin/scenarios/ehcache-2.x-scenario/configuration.yml
new file mode 100644
index 000000000..708a55dd9
--- /dev/null
+++ b/test/plugin/scenarios/ehcache-2.x-scenario/configuration.yml
@@ -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: tomcat
+entryService: http://localhost:8080/ehcache-2.x-scenario/case/ehcache
+healthCheck: http://localhost:8080/ehcache-2.x-scenario/healthCheck
+framework: ehcache-2.x
diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/pom.xml b/test/plugin/scenarios/ehcache-2.x-scenario/pom.xml
new file mode 100644
index 000000000..3eadc99ae
--- /dev/null
+++ b/test/plugin/scenarios/ehcache-2.x-scenario/pom.xml
@@ -0,0 +1,77 @@
+
+
+
+ 4.0.0
+
+ org.apache.skywalking
+ ehcache-2.x-scenario
+ 5.0.0
+ war
+
+
+ UTF-8
+ 1.8
+
+
+ ehcache
+ 2.10.4
+
+
+ skywalking-ehcache-2.x-scenario
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+ provided
+
+
+ org.apache.logging.log4j
+ log4j-api
+ 2.8.1
+
+
+ org.apache.logging.log4j
+ log4j-core
+ 2.8.1
+
+
+ net.sf.ehcache
+ ehcache
+ ${test.framework.version}
+
+
+
+
+ ehcache-2.x-scenario
+
+
+ maven-compiler-plugin
+
+ ${compiler.version}
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/ehcache/v2/CaseServlet.java b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/ehcache/v2/CaseServlet.java
new file mode 100644
index 000000000..3dfc50891
--- /dev/null
+++ b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/ehcache/v2/CaseServlet.java
@@ -0,0 +1,73 @@
+/*
+ * 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.ehcache.v2;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+public class CaseServlet extends HttpServlet {
+
+ CacheManager cacheManager = CacheManager.create(CaseServlet.class.getResource("/cache.xml"));
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ Cache cache = cacheManager.getCache("testCache");
+
+ String objectKey = "dataKey";
+
+ Element el = new Element(objectKey, "2");
+
+ // EhcacheOperateElementInterceptor
+ cache.put(el);
+
+ // EhcacheOperateObjectInterceptor
+ cache.get(objectKey);
+
+ // EhcacheOperateAllInterceptor
+ cache.putAll(Arrays.asList(new Element[] {el}));
+
+ // EhcacheLockInterceptor
+ try {
+ boolean success = cache.tryReadLockOnKey(objectKey, 300);
+ } catch (InterruptedException e) {
+ } finally {
+ cache.releaseReadLockOnKey(objectKey);
+ }
+
+ PrintWriter printWriter = resp.getWriter();
+ printWriter.write("success");
+ printWriter.flush();
+ printWriter.close();
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ doGet(req, resp);
+ }
+
+}
diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/ehcache/v2/HealthCheckServlet.java b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/ehcache/v2/HealthCheckServlet.java
new file mode 100644
index 000000000..51bb5102a
--- /dev/null
+++ b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/ehcache/v2/HealthCheckServlet.java
@@ -0,0 +1,40 @@
+/*
+ * 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.ehcache.v2;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class HealthCheckServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ PrintWriter writer = resp.getWriter();
+ writer.write("Success");
+ writer.flush();
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ doGet(req, resp);
+ }
+}
diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/src/main/resources/cache.xml b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/resources/cache.xml
new file mode 100644
index 000000000..8725b6f7d
--- /dev/null
+++ b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/resources/cache.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/src/main/resources/log4j2.xml b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..4c6c06d40
--- /dev/null
+++ b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/resources/log4j2.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/src/main/webapp/WEB-INF/web.xml b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 000000000..1dde5b37e
--- /dev/null
+++ b/test/plugin/scenarios/ehcache-2.x-scenario/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,45 @@
+
+
+ skywalking-ehcache-2.x-scenario
+
+
+ caseServlet
+ org.apache.skywalking.apm.testcase.ehcache.v2.CaseServlet
+
+
+ caseServlet
+ /case/ehcache
+
+
+
+ healthCheck
+ org.apache.skywalking.apm.testcase.ehcache.v2.HealthCheckServlet
+
+
+ healthCheck
+ /healthCheck
+
+
+
+
+
diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/support-version.list b/test/plugin/scenarios/ehcache-2.x-scenario/support-version.list
new file mode 100644
index 000000000..a28040a0f
--- /dev/null
+++ b/test/plugin/scenarios/ehcache-2.x-scenario/support-version.list
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+2.10.6
+2.10.5
+2.10.4
+2.10.3
+2.10.2.2.21
+2.10.2
+2.10.1
+2.10.0
+2.9.1
+2.9.0
+2.8.9
+2.8.8
+2.8.6
+2.8.5
+2.8.4
+2.8.3
+2.8.2
+2.8.1
+2.8.0