diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheCacheNameInterceptor.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheCacheNameInterceptor.java new file mode 100644 index 000000000..39e0a66fe --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcacheCacheNameInterceptor.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.plugin.ehcache.v2; + +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 java.lang.reflect.Method; + +public class EhcacheCacheNameInterceptor implements InstanceMethodsAroundInterceptor { + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + Object ret) throws Throwable { + String name = (String) allArguments[0]; + objInst.setSkyWalkingDynamicField(new EhcacheEnhanceInfo(name)); + return ret; + } + + @Override + public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + } +} diff --git a/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcachePrivateConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcachePrivateConstructorInterceptor.java new file mode 100644 index 000000000..6610332bf --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/ehcache-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/ehcache/v2/EhcachePrivateConstructorInterceptor.java @@ -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. + * + */ + +package org.apache.skywalking.apm.plugin.ehcache.v2; + +import net.sf.ehcache.Cache; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +public class EhcachePrivateConstructorInterceptor implements InstanceConstructorInterceptor { + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + Cache cache = (Cache) allArguments[0]; + + // get cache name + if (cache != null && cache.getCacheConfiguration() != null) { + objInst.setSkyWalkingDynamicField(new EhcacheEnhanceInfo(cache.getCacheConfiguration().getName())); + } + } +} 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 index c8883cc46..7f209b468 100644 --- 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 @@ -28,6 +28,7 @@ import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; +import static net.bytebuddy.matcher.ElementMatchers.isPrivate; import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; /** @@ -37,6 +38,7 @@ public class EhcachePluginInstrumentation extends ClassInstanceMethodsEnhancePlu 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"; + public static final String PRIVATE_CONSTRUCTOR_CLASS_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.ehcache.v2.EhcachePrivateConstructorInterceptor"; // get and put value public static final String PUT_CACHE_ENHANCE_METHOD = "put"; @@ -69,6 +71,10 @@ public class EhcachePluginInstrumentation extends ClassInstanceMethodsEnhancePlu 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"; + // cache name + public static final String CACHE_NAME_ENHANCE_METHOD = "setName"; + public static final String CACHE_NAME_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.ehcache.v2.EhcacheCacheNameInterceptor"; + @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { return new ConstructorInterceptPoint[] { @@ -82,6 +88,17 @@ public class EhcachePluginInstrumentation extends ClassInstanceMethodsEnhancePlu public String getConstructorInterceptor() { return CONSTRUCTOR_CLASS_INTERCEPT_CLASS; } + }, + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return isPrivate().and(takesArgument(0, named("net.sf.ehcache.Cache"))); + } + + @Override + public String getConstructorInterceptor() { + return PRIVATE_CONSTRUCTOR_CLASS_INTERCEPT_CLASS; + } } }; } @@ -89,6 +106,23 @@ public class EhcachePluginInstrumentation extends ClassInstanceMethodsEnhancePlu @Override public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(CACHE_NAME_ENHANCE_METHOD).and(takesArgument(0, String.class)); + } + + @Override + public String getMethodsInterceptor() { + return CACHE_NAME_INTERCEPTOR_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + + }, new InstanceMethodsInterceptPoint() { @Override public ElementMatcher getMethodsMatcher() { 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 index 555dc4b35..a612b9c3e 100644 --- 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 @@ -45,6 +45,8 @@ import static org.apache.skywalking.apm.plugin.ehcache.v2.define.EhcachePluginIn import static org.apache.skywalking.apm.plugin.ehcache.v2.define.EhcachePluginInstrumentation.READ_LOCK_TRY_ENHANCE_METHOD; import static org.apache.skywalking.apm.plugin.ehcache.v2.define.EhcachePluginInstrumentation.WRITE_LOCK_RELEASE_ENHANCE_METHOD; import static org.apache.skywalking.apm.plugin.ehcache.v2.define.EhcachePluginInstrumentation.WRITE_LOCK_TRY_ENHANCE_METHOD; +import static org.apache.skywalking.apm.plugin.ehcache.v2.define.EhcachePluginInstrumentation.CACHE_NAME_ENHANCE_METHOD; +import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; @RunWith(PowerMockRunner.class) @@ -64,10 +66,13 @@ public class EhcacheInterceptorTest { private EhcacheOperateAllInterceptor operateAllInterceptor; private EhcacheLockInterceptor lockInterceptor; private EhcacheConstructorInterceptor constructorInterceptor; + private EhcachePrivateConstructorInterceptor privateConstructorInterceptor; + private EhcacheCacheNameInterceptor cacheNameInterceptor; private Object[] operateObjectArguments; private Object[] operateElementArguments; private Object[] tryLockArguments; private Object[] releaseLockArguments; + private Object[] cacheNameArguments; private Exception exception; @@ -80,14 +85,19 @@ public class EhcacheInterceptorTest { private Method releaseReadLockMethod; private Method releaseWriteLockMethod; + private Method setNameMethod; + private EnhancedInstance enhancedInstance = new EnhancedInstance() { + EhcacheEnhanceInfo ehcacheEnhanceInfo; + @Override public Object getSkyWalkingDynamicField() { - return new EhcacheEnhanceInfo(CACHE_NAME); + return ehcacheEnhanceInfo; } @Override public void setSkyWalkingDynamicField(Object value) { + ehcacheEnhanceInfo = (EhcacheEnhanceInfo) value; } }; @@ -97,6 +107,8 @@ public class EhcacheInterceptorTest { operateElementInterceptor = new EhcacheOperateElementInterceptor(); operateAllInterceptor = new EhcacheOperateAllInterceptor(); constructorInterceptor = new EhcacheConstructorInterceptor(); + privateConstructorInterceptor = new EhcachePrivateConstructorInterceptor(); + cacheNameInterceptor = new EhcacheCacheNameInterceptor(); lockInterceptor = new EhcacheLockInterceptor(); exception = new Exception(); @@ -108,6 +120,7 @@ public class EhcacheInterceptorTest { 3000 }; releaseLockArguments = new Object[] {"dataKey"}; + cacheNameArguments = new Object[] {"cacheName"}; putCacheMethod = Whitebox.getMethods(Cache.class, PUT_CACHE_ENHANCE_METHOD)[0]; getCacheMethod = Whitebox.getMethods(Cache.class, GET_CACHE_ENHANCE_METHOD)[0]; @@ -117,6 +130,10 @@ public class EhcacheInterceptorTest { 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]; + + setNameMethod = Whitebox.getMethods(Cache.class, CACHE_NAME_ENHANCE_METHOD)[0]; + + enhancedInstance.setSkyWalkingDynamicField(new EhcacheEnhanceInfo(CACHE_NAME)); } @Test @@ -124,6 +141,20 @@ public class EhcacheInterceptorTest { constructorInterceptor.onConstruct(enhancedInstance, new Object[] {new CacheConfiguration(CACHE_NAME, 20)}); } + @Test + public void assertPrivateConstruct() throws Throwable { + privateConstructorInterceptor.onConstruct(enhancedInstance, new Object[] {new Cache(new CacheConfiguration(CACHE_NAME, 20))}); + } + + @Test + public void assertSetNameSuccess() throws Throwable { + cacheNameInterceptor.beforeMethod(enhancedInstance, setNameMethod, cacheNameArguments, null, null); + cacheNameInterceptor.handleMethodException(enhancedInstance, setNameMethod, null, null, exception); + cacheNameInterceptor.afterMethod(enhancedInstance, setNameMethod, cacheNameArguments, null, null); + + Assert.assertThat(((EhcacheEnhanceInfo) enhancedInstance.getSkyWalkingDynamicField()).getCacheName(), equalTo("cacheName")); + } + @Test public void assertPutSuccess() throws Throwable { // put arguments diff --git a/test/plugin/scenarios/ehcache-2.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/ehcache-2.x-scenario/config/expectedData.yaml index b2a077a07..94e7a9e93 100644 --- a/test/plugin/scenarios/ehcache-2.x-scenario/config/expectedData.yaml +++ b/test/plugin/scenarios/ehcache-2.x-scenario/config/expectedData.yaml @@ -100,6 +100,21 @@ segmentItems: peerId: 0 tags: - {key: db.statement, value: dataKey} + - operationName: Ehcache/put/testCache2 + operationId: 0 + parentSpanId: 0 + spanId: 6 + 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 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 index d29fd9054..60c998dbe 100644 --- 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 @@ -58,6 +58,14 @@ public class CaseServlet extends HttpServlet { cache.releaseReadLockOnKey(objectKey); } + // EhcacheCacheNameInterceptor + cacheManager.addCacheIfAbsent("testCache2"); + + Cache cloneCache = cacheManager.getCache("testCache2"); + + // EhcacheOperateElementInterceptor + cloneCache.put(el); + PrintWriter printWriter = resp.getWriter(); printWriter.write("success"); printWriter.flush();