From e09110bc482450d7ca99abc7ed1cf91c01b65239 Mon Sep 17 00:00:00 2001 From: Jongho Moon Date: Wed, 19 Nov 2014 17:43:48 +0900 Subject: [PATCH] [#49] Created pinpoint-test project. Tested pinoint-arcus project and fixed bugs --- .gitignore | 1 + arcus/pom.xml | 7 +- .../pinpoint/plugin/arcus/ArcusPlugin.java | 192 ++++++++++++++++-- .../arcus/interceptor/ApiInterceptor.java | 6 +- .../interceptor/FutureGetInterceptor.java | 4 - ...n.pinpoint.bootstrap.plugin.ProfilerPlugin | 1 + .../pinpoint/plugin/arcus/ArcusPluginIT.java | 58 ++++++ ...CacheGetFutureModifierIntegrationTest.java | 2 +- .../arcus/interceptor/ApiInterceptorTest.java | 2 +- ...erationTransitionStateInterceptorTest.java | 2 +- .../interceptor/FutureGetInterceptorTest.java | 2 +- arcus/src/test/resources/pinpoint-test.config | 186 +++++++++++++++++ .../interceptor/InterceptorRegistry.java | 18 +- .../interceptor/SimpleAfterInterceptor.java | 2 +- .../interceptor/SimpleBeforeInterceptor.java | 2 +- .../interceptor/SimpleInterceptor.java | 5 + .../bootstrap/plugin/BasicClassEditor.java | 15 +- .../bootstrap/plugin/ClassEditorBuilder.java | 46 +++-- .../plugin/ConditionalClassEditor.java | 11 +- .../plugin/DefaultInterceptorFactory.java | 20 +- .../plugin/DefaultMetadataInjector.java | 27 ++- .../bootstrap/plugin/ProfilerPlugin.java | 2 +- .../SpanSimpleAroundInterceptorTest.java | 7 +- .../plugin/ClassEditorBuilderTest.java | 4 +- .../plugin/DefaultInterceptorFactoryTest.java | 28 +-- plugins/.gitignore | 2 - plugins/pom.xml | 22 -- pom.xml | 24 +-- profiler/pom.xml | 2 +- .../ClassFileTransformerDispatcher.java | 26 ++- .../pinpoint/profiler/DefaultAgent.java | 13 +- .../interceptor/bci/JavaAssistClass.java | 97 +++++---- .../profiler/plugin/ClassEditorAdaptor.java | 37 ++-- .../pinpoint/profiler/util/ForkedJUnit.java | 100 +++++++++ .../pinpoint/profiler/util/PinpointAgent.java | 12 ++ .../profiler/util/PinpointConfig.java | 12 ++ test/pom.xml | 8 +- .../pinpoint/test/fork/ExcludeLibraries.java | 12 ++ .../nhn/pinpoint/test/fork/ForkRunner.java | 113 +++++++++-- .../nhn/pinpoint/test/fork/ForkedJUnit.java | 64 +++++- .../test/fork/OnChildClassLoader.java | 11 + .../pinpoint/test/fork/PinpointAgentPath.java | 6 +- .../pinpoint/test/fork/PinpointConfig.java | 2 +- .../nhn/pinpoint/test/fork/WithLibraries.java | 12 ++ 44 files changed, 981 insertions(+), 244 deletions(-) create mode 100644 arcus/src/main/resources/META-INF/services/com.nhn.pinpoint.bootstrap.plugin.ProfilerPlugin create mode 100644 arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/ArcusPluginIT.java create mode 100644 arcus/src/test/resources/pinpoint-test.config create mode 100644 bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleInterceptor.java delete mode 100644 plugins/.gitignore delete mode 100644 plugins/pom.xml create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/util/ForkedJUnit.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/util/PinpointAgent.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/util/PinpointConfig.java create mode 100644 test/src/main/java/com/nhn/pinpoint/test/fork/ExcludeLibraries.java create mode 100644 test/src/main/java/com/nhn/pinpoint/test/fork/OnChildClassLoader.java create mode 100644 test/src/main/java/com/nhn/pinpoint/test/fork/WithLibraries.java diff --git a/.gitignore b/.gitignore index aa77d55f3..ee734eb46 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /*.iml /deploy /target +/build/ diff --git a/arcus/pom.xml b/arcus/pom.xml index 3c2cda10b..b3fb1946f 100644 --- a/arcus/pom.xml +++ b/arcus/pom.xml @@ -3,11 +3,11 @@ 4.0.0 com.nhn.pinpoint - pinpoint-plugins + pom 1.0.4-SNAPSHOT - pinpoint-arcus-plugin + pinpoint-arcus pinpoint arcus plugin jar @@ -92,8 +92,9 @@ org.apache.maven.plugins maven-jar-plugin + - ${pinpiont-plugin-dir} + ../${pinpoint.agent.plugin.directory} diff --git a/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/ArcusPlugin.java b/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/ArcusPlugin.java index daf8e8a97..8f43d9c0b 100644 --- a/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/ArcusPlugin.java +++ b/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/ArcusPlugin.java @@ -4,43 +4,199 @@ import java.util.ArrayList; import java.util.List; import com.nhn.pinpoint.bootstrap.instrument.InstrumentClass; -import com.nhn.pinpoint.bootstrap.instrument.MethodInfo; -import com.nhn.pinpoint.bootstrap.interceptor.ParameterExtractor; import com.nhn.pinpoint.bootstrap.plugin.ClassEditor; import com.nhn.pinpoint.bootstrap.plugin.ClassEditorBuilder; -import com.nhn.pinpoint.bootstrap.plugin.ClassEditorFactoryMapping; import com.nhn.pinpoint.bootstrap.plugin.Condition; -import com.nhn.pinpoint.bootstrap.plugin.ParameterExtractorFactory; import com.nhn.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.nhn.pinpoint.bootstrap.plugin.ProfilerPluginContext; +import com.nhn.pinpoint.plugin.arcus.filter.ArcusMethodFilter; +import com.nhn.pinpoint.plugin.arcus.filter.FrontCacheMemcachedMethodFilter; +import com.nhn.pinpoint.plugin.arcus.filter.MemcachedMethodFilter; // TODO split arcus plugin and memcached plugin public class ArcusPlugin implements ProfilerPlugin { @Override - public List getClassEditorMappings(ProfilerPluginContext context) { + public List getClassEditors(ProfilerPluginContext context) { boolean arcus = context.getConfig().isArucs(); boolean memcached = context.getConfig().isMemcached(); - List editors = new ArrayList(); + List editors = new ArrayList(); - if (arcus) { - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.ArcusClient", "com.nhn.pinpoint.plugin.arcus.ArcusClientEditorFactory")); - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.internal.CollectionFuture", "com.nhn.pinpoint.plugin.arcus.FutureEditorFactory")); + if (arcus) { + editors.add(getArcusClientEditor(context)); + editors.add(getCollectionFutureEditor(context)); } if (arcus || memcached) { - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.protocol.BaseOperationImpl", "com.nhn.pinpoint.plugin.arcus.BaseOperationImplEditorFactory")); - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.CacheManager", "com.nhn.pinpoint.plugin.arcus.BaseCacheManagerEditorFactory")); + editors.add(getBaseOperationImplEditor(context)); + editors.add(getCacheManagerEditor(context)); - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.internal.GetFuture", "com.nhn.pinpoint.plugin.arcus.FutureEditorFactory")); - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.internal.ImmediateFuture", "com.nhn.pinpoint.plugin.arcus.FutureEditorFactory")); - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.internal.OperationFuture", "com.nhn.pinpoint.plugin.arcus.FutureEditorFactory")); + editors.add(getGetFutureEditor(context)); + // TODO ImmedateFuture doesn't have setOperation(Operation) method. +// editors.add(getImmediateFutureEditor(context)); + editors.add(getOperationFutureEditor(context)); - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.plugin.FrontCacheGetFuture", "com.nhn.pinpoint.plugin.arcus.FrontCacheGetFutureEditorFactory")); - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.plugin.FrontCacheMemcachedClient", "com.nhn.pinpoint.plugin.arcus.FrontCacheMemcachedClientEditorFactory")); - editors.add(new ClassEditorFactoryMapping("net.spy.memcached.MemcachedClient", "com.nhn.pinpoint.plugin.arcus.MemcachedClientEditorFactory")); + editors.add(getFrontCacheGetFutureEditor(context)); + editors.add(getFrontCacheMemcachedClientEditor(context)); + editors.add(getMemcachedClientEditor(context)); } return editors; } -} + + private ClassEditor getArcusClientEditor(ProfilerPluginContext context) { + boolean traceArcusKey = context.getConfig().isArucsKeyTrace(); + ClassEditorBuilder builder = context.newClassEditorBuilder(); + + builder.edit("net.spy.memcached.ArcusClient"); + builder.when(new Condition() { + @Override + public boolean check(InstrumentClass target) { + return target.hasMethod("addOp", new String[] {"java.lang.String", "net.spy.memcached.ops.Operation"}, "net.spy.memcached.ops.Operation"); + } + }); + + builder.intercept("setCacheManager", "net.spy.memcached.CacheManager") + .with("com.nhn.pinpoint.plugin.arcus.interceptor.SetCacheManagerInterceptor"); + + builder.interceptMethodsFilteredBy(new ArcusMethodFilter()) + .with("com.nhn.pinpoint.plugin.arcus.interceptor.ApiInterceptor") + .in(Commons.ARCUS_SCOPE) + .using(traceArcusKey ? Commons.ARCUS_KEY_EXTRACTOR_FACTORY : null); + + return builder.build(); + } + + private ClassEditor getCacheManagerEditor(ProfilerPluginContext context) { + ClassEditorBuilder builder = context.newClassEditorBuilder(); + + builder.edit("net.spy.memcached.CacheManager"); + + builder.inject("com.nhn.pinpoint.plugin.arcus.accessor.ServiceCodeAccessor"); + + builder.interceptConstructor("java.lang.String", "java.lang.String", "net.spy.memcached.ConnectionFactoryBuilder", "java.util.concurrent.CountDownLatch", "int", "int") + .with("com.nhn.pinpoint.plugin.arcus.interceptor.CacheManagerConstructInterceptor"); + + return builder.build(); + } + + + private ClassEditor getBaseOperationImplEditor(ProfilerPluginContext context) { + ClassEditorBuilder builder = context.newClassEditorBuilder(); + + builder.edit("net.spy.memcached.protocol.BaseOperationImpl"); + + builder.inject("com.nhn.pinpoint.plugin.arcus.accessor.ServiceCodeAccessor"); + + return builder.build(); + } + + private ClassEditor getFrontCacheGetFutureEditor(ProfilerPluginContext context) { + ClassEditorBuilder builder = context.newClassEditorBuilder(); + + builder.edit("net.spy.memcached.plugin.FrontCacheGetFuture"); + + builder.inject("com.nhn.pinpoint.plugin.arcus.accessor.CacheNameAccessor"); + builder.inject("com.nhn.pinpoint.plugin.arcus.accessor.CacheKeyAccessor"); + + builder.interceptConstructor("net.sf.ehcache.Element") + .with("com.nhn.pinpoint.plugin.arcus.interceptor.FrontCacheGetFutureConstructInterceptor"); + builder.intercept("get", "long", "java.util.concurrent.TimeUnit") + .with("com.nhn.pinpoint.plugin.arcus.interceptor.FrontCacheGetFutureGetInterceptor") + .in(Commons.ARCUS_SCOPE); + builder.intercept("get") + .with("com.nhn.pinpoint.plugin.arcus.interceptor.FrontCacheGetFutureGetInterceptor") + .in(Commons.ARCUS_SCOPE); + + return builder.build(); + } + + private ClassEditor getFrontCacheMemcachedClientEditor(ProfilerPluginContext context) { + boolean traceArcusKey = context.getConfig().isArucsKeyTrace(); + ClassEditorBuilder builder = context.newClassEditorBuilder(); + + builder.edit("net.spy.memcached.plugin.FrontCacheMemcachedClient"); + builder.when(new Condition() { + + @Override + public boolean check(InstrumentClass target) { + return target.hasDeclaredMethod("putFrontCache", new String[] { "java.lang.String", "java.util.concurrent.Future", "long" }); + } + + }); + + builder.interceptMethodsFilteredBy(new FrontCacheMemcachedMethodFilter()) + .with("com.nhn.pinpoint.plugin.arcus.interceptor.ApiInterceptor") + .in(Commons.ARCUS_SCOPE) + .using(traceArcusKey ? Commons.ARCUS_KEY_EXTRACTOR_FACTORY : null); + + return builder.build(); + } + + + private ClassEditor getMemcachedClientEditor(ProfilerPluginContext context) { + boolean traceArcusKey = context.getConfig().isArucsKeyTrace(); + ClassEditorBuilder builder = context.newClassEditorBuilder(); + + builder.edit("net.spy.memcached.MemcachedClient"); + builder.when(new Condition() { + + @Override + public boolean check(InstrumentClass target) { + return target.hasDeclaredMethod("addOp", new String[] { "java.lang.String", "net.spy.memcached.ops.Operation" }); + } + + }); + + + builder.inject("com.nhn.pinpoint.plugin.arcus.accessor.ServiceCodeAccessor"); + + builder.intercept("addOp", "java.lang.String", "net.spy.memcached.ops.Operation") + .with("com.nhn.pinpoint.plugin.arcus.interceptor.AddOpInterceptor"); + + builder.interceptMethodsFilteredBy(new MemcachedMethodFilter()) + .with("com.nhn.pinpoint.plugin.arcus.interceptor.ApiInterceptor") + .in(Commons.ARCUS_SCOPE) + .using(traceArcusKey ? Commons.ARCUS_KEY_EXTRACTOR_FACTORY : null); + + return builder.build(); + } + + private ClassEditor getFutureEditor(ClassEditorBuilder builder) { + builder.inject("com.nhn.pinpoint.plugin.arcus.accessor.OperationAccessor"); + + builder.intercept("setOperation", "net.spy.memcached.ops.Operation") + .with("com.nhn.pinpoint.plugin.arcus.interceptor.FutureSetOperationInterceptor"); + + builder.intercept("get", "long", "java.util.concurrent.TimeUnit") + .with("com.nhn.pinpoint.plugin.arcus.interceptor.FutureGetInterceptor") + .in(Commons.ARCUS_SCOPE); + + return builder.build(); + } + + private ClassEditor getCollectionFutureEditor(ProfilerPluginContext context) { + ClassEditorBuilder builder = context.newClassEditorBuilder(); + builder.edit("net.spy.memcached.internal.CollectionFuture"); + return getFutureEditor(builder); + } + + private ClassEditor getGetFutureEditor(ProfilerPluginContext context) { + ClassEditorBuilder builder = context.newClassEditorBuilder(); + builder.edit("net.spy.memcached.internal.GetFuture"); + return getFutureEditor(builder); + } + + private ClassEditor getOperationFutureEditor(ProfilerPluginContext context) { + ClassEditorBuilder builder = context.newClassEditorBuilder(); + builder.edit("net.spy.memcached.internal.OperationFuture"); + return getFutureEditor(builder); + } + + private ClassEditor getImmediateFutureEditor(ProfilerPluginContext context) { + ClassEditorBuilder builder = context.newClassEditorBuilder(); + builder.edit("net.spy.memcached.internal.ImmediateFuture"); + return getFutureEditor(builder); + } + +} \ No newline at end of file diff --git a/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/interceptor/ApiInterceptor.java b/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/interceptor/ApiInterceptor.java index da9be4fc8..ae70e19c2 100644 --- a/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/interceptor/ApiInterceptor.java +++ b/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/interceptor/ApiInterceptor.java @@ -19,7 +19,11 @@ import com.nhn.pinpoint.plugin.arcus.accessor.ServiceCodeAccessor; */ public class ApiInterceptor extends SpanEventSimpleAroundInterceptor { private final ParameterExtractor parameterExtractor; - + + public ApiInterceptor() { + this(null); + } + public ApiInterceptor(ParameterExtractor parameterExtractor) { super(ApiInterceptor.class); this.parameterExtractor = parameterExtractor; diff --git a/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/interceptor/FutureGetInterceptor.java b/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/interceptor/FutureGetInterceptor.java index a6fad3a93..54da20a9e 100644 --- a/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/interceptor/FutureGetInterceptor.java +++ b/arcus/src/main/java/com/nhn/pinpoint/plugin/arcus/interceptor/FutureGetInterceptor.java @@ -8,14 +8,10 @@ import net.spy.memcached.ops.Operation; import com.nhn.pinpoint.bootstrap.context.Trace; import com.nhn.pinpoint.bootstrap.context.TraceContext; -import com.nhn.pinpoint.bootstrap.interceptor.ByteCodeMethodDescriptorSupport; import com.nhn.pinpoint.bootstrap.interceptor.MethodDescriptor; import com.nhn.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor; -import com.nhn.pinpoint.bootstrap.interceptor.TargetClassLoader; -import com.nhn.pinpoint.bootstrap.interceptor.TraceContextSupport; import com.nhn.pinpoint.bootstrap.logging.PLogger; import com.nhn.pinpoint.bootstrap.logging.PLoggerFactory; -import com.nhn.pinpoint.bootstrap.util.MetaObject; import com.nhn.pinpoint.common.ServiceType; import com.nhn.pinpoint.plugin.arcus.accessor.OperationAccessor; import com.nhn.pinpoint.plugin.arcus.accessor.ServiceCodeAccessor; diff --git a/arcus/src/main/resources/META-INF/services/com.nhn.pinpoint.bootstrap.plugin.ProfilerPlugin b/arcus/src/main/resources/META-INF/services/com.nhn.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000..7720c40c9 --- /dev/null +++ b/arcus/src/main/resources/META-INF/services/com.nhn.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.nhn.pinpoint.plugin.arcus.ArcusPlugin \ No newline at end of file diff --git a/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/ArcusPluginIT.java b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/ArcusPluginIT.java new file mode 100644 index 000000000..1d6f78a41 --- /dev/null +++ b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/ArcusPluginIT.java @@ -0,0 +1,58 @@ +package com.nhn.pinpoint.plugin.arcus; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.nhn.pinpoint.plugin.arcus.accessor.CacheKeyAccessor; +import com.nhn.pinpoint.plugin.arcus.accessor.CacheNameAccessor; +import com.nhn.pinpoint.plugin.arcus.accessor.OperationAccessor; +import com.nhn.pinpoint.plugin.arcus.accessor.ServiceCodeAccessor; +import com.nhn.pinpoint.test.fork.ForkRunner; +import com.nhn.pinpoint.test.fork.OnChildClassLoader; +import com.nhn.pinpoint.test.fork.PinpointAgentPath; +import com.nhn.pinpoint.test.fork.PinpointConfig; + +@RunWith(ForkRunner.class) +@PinpointConfig("target/test-classes/pinpoint-test.config") +@PinpointAgentPath("../build/pinpoint-agent") +@OnChildClassLoader +public class ArcusPluginIT { + + // TODO how to test intercpetor? + + @Test + public void test() throws Exception { + + Class arcusClient = Class.forName("net.spy.memcached.ArcusClient"); + + Class cacheManager = Class.forName("net.spy.memcached.CacheManager"); + assertTrue(ServiceCodeAccessor.class.isAssignableFrom(cacheManager)); + + Class collectionFuture = Class.forName("net.spy.memcached.internal.CollectionFuture"); + assertTrue(OperationAccessor.class.isAssignableFrom(collectionFuture)); + + Class baseOperationImpl = Class.forName("net.spy.memcached.protocol.BaseOperationImpl"); + assertTrue(ServiceCodeAccessor.class.isAssignableFrom(baseOperationImpl)); + + + Class getFuture = Class.forName("net.spy.memcached.internal.GetFuture"); + assertTrue(OperationAccessor.class.isAssignableFrom(getFuture)); + + Class immediateFuture = Class.forName("net.spy.memcached.internal.ImmediateFuture"); +// assertTrue(OperationAccessor.class.isAssignableFrom(immediateFuture)); + + Class operationFuture = Class.forName("net.spy.memcached.internal.OperationFuture"); + assertTrue(OperationAccessor.class.isAssignableFrom(operationFuture)); + + Class frontCacheGetFuture = Class.forName("net.spy.memcached.plugin.FrontCacheGetFuture"); + assertTrue(CacheNameAccessor.class.isAssignableFrom(frontCacheGetFuture)); + assertTrue(CacheKeyAccessor.class.isAssignableFrom(frontCacheGetFuture)); + + Class frontCacheMemcachedClient = Class.forName("net.spy.memcached.plugin.FrontCacheMemcachedClient"); + + Class memcachedClient = Class.forName("net.spy.memcached.MemcachedClient"); + assertTrue(ServiceCodeAccessor.class.isAssignableFrom(memcachedClient)); + } +} \ No newline at end of file diff --git a/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/FrontCacheGetFutureModifierIntegrationTest.java b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/FrontCacheGetFutureModifierIntegrationTest.java index 30ccc3cd0..5f76c77cc 100644 --- a/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/FrontCacheGetFutureModifierIntegrationTest.java +++ b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/FrontCacheGetFutureModifierIntegrationTest.java @@ -1,4 +1,4 @@ -package com.nhn.pinpoint.profiler.modifier.arcus; +package com.nhn.pinpoint.plugin.arcus; import com.nhn.pinpoint.common.bo.SpanEventBo; import com.nhn.pinpoint.profiler.junit4.BasePinpointTest; diff --git a/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/ApiInterceptorTest.java b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/ApiInterceptorTest.java index eb02d627c..bb761ca70 100644 --- a/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/ApiInterceptorTest.java +++ b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/ApiInterceptorTest.java @@ -1,4 +1,4 @@ -package com.nhn.pinpoint.profiler.modifier.arcus.interceptor; +package com.nhn.pinpoint.plugin.arcus.interceptor; import static org.mockito.Mockito.*; diff --git a/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/BaseOperationTransitionStateInterceptorTest.java b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/BaseOperationTransitionStateInterceptorTest.java index 5c42fc744..8d8ec3677 100644 --- a/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/BaseOperationTransitionStateInterceptorTest.java +++ b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/BaseOperationTransitionStateInterceptorTest.java @@ -1,4 +1,4 @@ -package com.nhn.pinpoint.profiler.modifier.arcus.interceptor; +package com.nhn.pinpoint.plugin.arcus.interceptor; import junit.framework.Assert; import net.spy.memcached.ops.OperationState; diff --git a/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/FutureGetInterceptorTest.java b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/FutureGetInterceptorTest.java index 1cf2750d3..2979ad5f6 100644 --- a/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/FutureGetInterceptorTest.java +++ b/arcus/src/test/java/com/nhn/pinpoint/plugin/arcus/interceptor/FutureGetInterceptorTest.java @@ -1,4 +1,4 @@ -package com.nhn.pinpoint.profiler.modifier.arcus.interceptor; +package com.nhn.pinpoint.plugin.arcus.interceptor; import static org.junit.Assert.*; import static org.mockito.Mockito.*; diff --git a/arcus/src/test/resources/pinpoint-test.config b/arcus/src/test/resources/pinpoint-test.config new file mode 100644 index 000000000..b331ae8e0 --- /dev/null +++ b/arcus/src/test/resources/pinpoint-test.config @@ -0,0 +1,186 @@ +# +# Pinpoint agent configuration +# (Phase : local) +# + +########################################################### +# Collector server # +########################################################### +# 로컬 +profiler.collector.ip=127.0.0.1 +# 개발 +#profiler.collector.ip=10.64.84.188 +# 운영 +#profiler.collector.ip=10.25.149.249 + +profiler.collector.udpspan.port=9996 +profiler.collector.udp.port=9995 +profiler.collector.tcp.port=9994 + + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +profiler.jvm.collect.interval=1000 + +profiler.sampling.enable=true + +# 아래 지정한 값중 한 개의 트랜잭션을 수집합니다. (예를들어 1로 지정하면 100%수집, 2로 지정하면 50%수집 셈) +profiler.sampling.rate=1 + +# span을 Io에 flush할 경우 buffering 여부 +profiler.io.buffering.enable=true + +# buffering 시 몇개 까지 저장할지 여부 +profiler.io.buffering.buffersize=20 + + + +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 + +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 + +profiler.heartbeat.interval=300000 + +# Tcp Data Command 허용 여부 +profiler.tcpdatasender.command.accept.enable=true + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + + +########################################################### +# user defined classes # +########################################################### +profiler.include=com.nhn.pinpoint.testweb.controller.*,com.nhn.pinpoint.testweb.MyClass + + +########################################################### +# JDBC # +########################################################### +profiler.jdbc=true +profiler.jdbc.sqlcachesize=1024 +profiler.jdbc.maxsqlbindvaluesize=1024 + +# +# MYSQL +# +profiler.jdbc.mysql=true +profiler.jdbc.mysql.setautocommit=true +profiler.jdbc.mysql.commit=true +profiler.jdbc.mysql.rollback=true + +# +# MSSQL +# +profiler.jdbc.mssql=false + +# +# Oracle +# +profiler.jdbc.oracle=true +profiler.jdbc.oracle.setautocommit=true +profiler.jdbc.oracle.commit=true +profiler.jdbc.oracle.rollback=true + +# +# CUBRID +# +profiler.jdbc.cubrid=true +profiler.jdbc.cubrid.setautocommit=true +profiler.jdbc.cubrid.commit=true +profiler.jdbc.cubrid.rollback=true + +# +# DBCP +# +profiler.jdbc.dbcp=true +profiler.jdbc.dbcp.connectionclose=true + + +########################################################### +# Apache HTTP Client 4.x # +########################################################### +profiler.apache.httpclient4=true +profiler.apache.httpclient4.cookie=true + +# cookie를 언제 덤프할지 결정. ALWAYS or EXCEPTION 2가지 +profiler.apache.httpclient4.cookie.dumptype=ALWAYS +profiler.apache.httpclient4.cookie.sampling.rate=1 + +# post, put의 entity를 덤프한다. 단 HttpEtity.isRepeatable()=true 인 Entity에 한정된다. +profiler.apache.httpclient4.entity=true + +# entity를 언제 덤프할지 결정. ALWAYS or EXCEPTION 2가지 +profiler.apache.httpclient4.entity.dumptype=ALWAYS +profiler.apache.httpclient4.entity.sampling.rate=1 + +profiler.apache.nio.httpclient4=true + + +########################################################### +# Ning Async HTTP Client # +########################################################### +profiler.ning.asynchttpclient=true +profiler.ning.asynchttpclient.cookie=true +profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS +profiler.ning.asynchttpclient.cookie.dumpsize=1024 +profiler.ning.asynchttpclient.cookie.sampling.rate=1 +profiler.ning.asynchttpclient.entity=true +profiler.ning.asynchttpclient.entity.dumptype=ALWAYS +profiler.ning.asynchttpclient.entity.dumpsize=1024 +profiler.ning.asynchttpclient.entity.sampling.rate=1 +profiler.ning.asynchttpclient.param=true +profiler.ning.asynchttpclient.param.dumptype=ALWAYS +profiler.ning.asynchttpclient.param.dumpsize=1024 +profiler.ning.asynchttpclient.param.sampling.rate=1 + + +########################################################### +# LINE+ baseframework # +########################################################### +profiler.line.game.netty.param.dumpsize=512 +profiler.line.game.netty.entity.dumpsize=512 + + +########################################################### +# Arcus # +########################################################### +profiler.arcus=true +profiler.arcus.keytrace=true + + +########################################################### +# Memcached # +########################################################### +profiler.memcached=true +profiler.memcached.keytrace=true + + +########################################################### +# ibatis # +########################################################### +profiler.orm.ibatis=true + + +########################################################### +# mybatis # +########################################################### +profiler.orm.mybatis=true + +########################################################### +# spring-beans +########################################################### +profiler.spring.beans=true +profiler.spring.beans.name.pattern=ma.*, outer +profiler.spring.beans.class.pattern=.*Morae +profiler.spring.beans.annotation=org.springframework.stereotype.Component \ No newline at end of file diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/InterceptorRegistry.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/InterceptorRegistry.java index d141c8075..c603479ca 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/InterceptorRegistry.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/InterceptorRegistry.java @@ -18,7 +18,7 @@ public class InterceptorRegistry { private final AtomicInteger id = new AtomicInteger(0); private final StaticAroundInterceptor[] index; - private final SimpleAroundInterceptor[] simpleIndex; + private final SimpleInterceptor[] simpleIndex; // private final ConcurrentMap nameIndex = new ConcurrentHashMap(); @@ -29,7 +29,7 @@ public class InterceptorRegistry { InterceptorRegistry(int max) { this.max = max; this.index = new StaticAroundInterceptor[max]; - this.simpleIndex = new SimpleAroundInterceptor[max]; + this.simpleIndex = new SimpleInterceptor[max]; } @@ -51,7 +51,7 @@ public class InterceptorRegistry { return id.getAndIncrement(); } - int addSimpleInterceptor0(SimpleAroundInterceptor interceptor) { + int addSimpleInterceptor0(SimpleInterceptor interceptor) { if (interceptor == null) { return -1; } @@ -59,7 +59,7 @@ public class InterceptorRegistry { if (newId >= max) { throw new IndexOutOfBoundsException("size=" + index.length + " id=" + id); } - + this.simpleIndex[newId] = interceptor; // this.nameIndex.put(interceptor.getClass().getName(), newId); return newId; @@ -74,8 +74,8 @@ public class InterceptorRegistry { return interceptor; } - SimpleAroundInterceptor getSimpleInterceptor0(int key) { - SimpleAroundInterceptor interceptor = simpleIndex[key]; + SimpleInterceptor getSimpleInterceptor0(int key) { + SimpleInterceptor interceptor = simpleIndex[key]; if (interceptor == null) { // 로직이 잘못되었을경우 에러가 발생하지 않도록 더미를 리턴. return DUMMY; @@ -109,7 +109,7 @@ public class InterceptorRegistry { public static Interceptor findInterceptor(int key) { - SimpleAroundInterceptor simpleInterceptor = REGISTRY.getSimpleInterceptor0(key); + SimpleInterceptor simpleInterceptor = REGISTRY.getSimpleInterceptor0(key); if (simpleInterceptor != null) { return simpleInterceptor; } @@ -124,12 +124,12 @@ public class InterceptorRegistry { return DUMMY; } - public static int addSimpleInterceptor(SimpleAroundInterceptor interceptor) { + public static int addSimpleInterceptor(SimpleInterceptor interceptor) { return REGISTRY.addSimpleInterceptor0(interceptor); } - public static SimpleAroundInterceptor getSimpleInterceptor(int key) { + public static SimpleInterceptor getSimpleInterceptor(int key) { return REGISTRY.getSimpleInterceptor0(key); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleAfterInterceptor.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleAfterInterceptor.java index f764192df..f95c04f79 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleAfterInterceptor.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleAfterInterceptor.java @@ -3,6 +3,6 @@ package com.nhn.pinpoint.bootstrap.interceptor; /** * @author emeroad */ -public interface SimpleAfterInterceptor extends Interceptor { +public interface SimpleAfterInterceptor extends SimpleInterceptor { void after(Object target, Object[] args, Object result, Throwable throwable); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleBeforeInterceptor.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleBeforeInterceptor.java index 534f40062..600ce1f88 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleBeforeInterceptor.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleBeforeInterceptor.java @@ -1,5 +1,5 @@ package com.nhn.pinpoint.bootstrap.interceptor; -public interface SimpleBeforeInterceptor extends Interceptor { +public interface SimpleBeforeInterceptor extends SimpleInterceptor { void before(Object target, Object[] args); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleInterceptor.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleInterceptor.java new file mode 100644 index 000000000..cd69bc154 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SimpleInterceptor.java @@ -0,0 +1,5 @@ +package com.nhn.pinpoint.bootstrap.interceptor; + +public interface SimpleInterceptor extends Interceptor { + +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/BasicClassEditor.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/BasicClassEditor.java index 9ad1953ae..02cb69748 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/BasicClassEditor.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/BasicClassEditor.java @@ -5,12 +5,14 @@ import java.util.List; import com.nhn.pinpoint.bootstrap.instrument.InstrumentClass; import com.nhn.pinpoint.exception.PinpointException; -public class BasicClassEditor implements ClassEditor { +public class BasicClassEditor implements DedicatedClassEditor { + private final String targetClassName; private final List metadataInjectors; private final List interceptorInjectors; - public BasicClassEditor(List metadataInjectors, List interceptorInjectors) { + public BasicClassEditor(String targetClassName, List metadataInjectors, List interceptorInjectors) { + this.targetClassName = targetClassName; this.metadataInjectors = metadataInjectors; this.interceptorInjectors = interceptorInjectors; } @@ -28,7 +30,14 @@ public class BasicClassEditor implements ClassEditor { return target.toBytecode(); } catch (Throwable t) { - throw new PinpointException("Fail to edit class", t); + throw new PinpointException("Fail to edit class: " + targetClassName, t); } } + + @Override + public String getTargetClassName() { + return targetClassName; + } + + } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ClassEditorBuilder.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ClassEditorBuilder.java index 92569e952..14bafbf33 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ClassEditorBuilder.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ClassEditorBuilder.java @@ -6,8 +6,6 @@ import java.util.List; import com.nhn.pinpoint.bootstrap.context.TraceContext; import com.nhn.pinpoint.bootstrap.instrument.ByteCodeInstrumentor; import com.nhn.pinpoint.bootstrap.instrument.MethodFilter; -import com.nhn.pinpoint.bootstrap.interceptor.Interceptor; -import com.nhn.pinpoint.bootstrap.interceptor.tracevalue.TraceValue; import com.nhn.pinpoint.bootstrap.plugin.MetadataInitializationStrategy.ByConstructor; public class ClassEditorBuilder { @@ -17,6 +15,7 @@ public class ClassEditorBuilder { private final List interceptorBuilders = new ArrayList(); private final List metadataBuilders = new ArrayList(); + private String targetClassName; private Condition condition; public ClassEditorBuilder(ByteCodeInstrumentor instrumentor, TraceContext traceContext) { @@ -24,13 +23,18 @@ public class ClassEditorBuilder { this.traceContext = traceContext; } - public ClassEditorBuilder editWhen(Condition condition) { + public ClassEditorBuilder edit(String targetClassName) { + this.targetClassName = targetClassName; + return this; + } + + public ClassEditorBuilder when(Condition condition) { this.condition = condition; return this; } - public InterceptorBuilder intercept(String methodName, Class... parameterTypes) { - InterceptorBuilder interceptorBuilder = new InterceptorBuilder(methodName, parameterTypes, null); + public InterceptorBuilder intercept(String methodName, String... parameterTypeNames) { + InterceptorBuilder interceptorBuilder = new InterceptorBuilder(methodName, parameterTypeNames, null); interceptorBuilders.add(interceptorBuilder); return interceptorBuilder; } @@ -41,19 +45,19 @@ public class ClassEditorBuilder { return interceptorBuilder; } - public InterceptorBuilder interceptConstructor(Class... parameterTypes) { - InterceptorBuilder interceptorBuilder = new InterceptorBuilder(null, parameterTypes, null); + public InterceptorBuilder interceptConstructor(String... parameterTypeNames) { + InterceptorBuilder interceptorBuilder = new InterceptorBuilder(null, parameterTypeNames, null); interceptorBuilders.add(interceptorBuilder); return interceptorBuilder; } - public MetadataBuilder inject(Class metadataType) { - MetadataBuilder metadataBuilder = new MetadataBuilder(metadataType); + public MetadataBuilder inject(String metadataAccessorName) { + MetadataBuilder metadataBuilder = new MetadataBuilder(metadataAccessorName); metadataBuilders.add(metadataBuilder); return metadataBuilder; } - public ClassEditor build() { + public DedicatedClassEditor build() { List metadataInjectors = new ArrayList(metadataBuilders.size()); for (MetadataBuilder builder : metadataBuilders) { @@ -66,7 +70,7 @@ public class ClassEditorBuilder { interceptorInjectors.add(builder.build()); } - ClassEditor editor = new BasicClassEditor(metadataInjectors, interceptorInjectors); + DedicatedClassEditor editor = new BasicClassEditor(targetClassName, metadataInjectors, interceptorInjectors); if (condition != null) { editor = new ConditionalClassEditor(condition, editor); @@ -80,16 +84,16 @@ public class ClassEditorBuilder { private final String[] parameterTypes; private final MethodFilter filter; - private Class interceptorClass; + private String interceptorClassName; private Condition condition; private String scopeName; private Object[] constructorArguments; private ParameterExtractorFactory parameterExtractorFactory; private boolean singleton; - public InterceptorBuilder(String methodName, Class[] parameterTypes, MethodFilter filter) { + public InterceptorBuilder(String methodName, String[] parameterTypeNames, MethodFilter filter) { this.methodName = methodName; - this.parameterTypes = TypeUtils.toClassNames(parameterTypes); + this.parameterTypes = parameterTypeNames; this.filter = filter; } @@ -98,8 +102,8 @@ public class ClassEditorBuilder { return this; } - public InterceptorBuilder with(Class interceptorClass) { - this.interceptorClass = interceptorClass; + public InterceptorBuilder with(String interceptorClassName) { + this.interceptorClassName = interceptorClassName; return this; } @@ -124,7 +128,7 @@ public class ClassEditorBuilder { } private InterceptorInjector build() { - InterceptorFactory interceptorFactory = new DefaultInterceptorFactory(instrumentor, traceContext, interceptorClass, constructorArguments, parameterExtractorFactory, scopeName); + InterceptorFactory interceptorFactory = new DefaultInterceptorFactory(instrumentor, traceContext, interceptorClassName, constructorArguments, parameterExtractorFactory, scopeName); InterceptorInjector injector; @@ -145,11 +149,11 @@ public class ClassEditorBuilder { } public class MetadataBuilder { - private final Class metadataType; + private final String metadataAccessorTypeName; private MetadataInitializationStrategy initializationStrategy; - public MetadataBuilder(Class metadataType) { - this.metadataType = metadataType; + public MetadataBuilder(String metadataAccessorTypeName) { + this.metadataAccessorTypeName = metadataAccessorTypeName; } public MetadataBuilder initializeWithDefaultConstructorOf(String className) { @@ -158,7 +162,7 @@ public class ClassEditorBuilder { } private MetadataInjector build() { - return new DefaultMetadataInjector(metadataType, initializationStrategy); + return new DefaultMetadataInjector(metadataAccessorTypeName, initializationStrategy); } } } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ConditionalClassEditor.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ConditionalClassEditor.java index 23e6132ef..c24efdf34 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ConditionalClassEditor.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ConditionalClassEditor.java @@ -2,11 +2,11 @@ package com.nhn.pinpoint.bootstrap.plugin; import com.nhn.pinpoint.bootstrap.instrument.InstrumentClass; -public class ConditionalClassEditor implements ClassEditor { +public class ConditionalClassEditor implements DedicatedClassEditor { private final Condition condition; - private final ClassEditor delegate; + private final DedicatedClassEditor delegate; - public ConditionalClassEditor(Condition condition, ClassEditor delegate) { + public ConditionalClassEditor(Condition condition, DedicatedClassEditor delegate) { this.condition = condition; this.delegate = delegate; } @@ -19,4 +19,9 @@ public class ConditionalClassEditor implements ClassEditor { return null; } + + @Override + public String getTargetClassName() { + return delegate.getTargetClassName(); + } } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultInterceptorFactory.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultInterceptorFactory.java index a2cfe3bf5..31b0b88cf 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultInterceptorFactory.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultInterceptorFactory.java @@ -22,17 +22,17 @@ public class DefaultInterceptorFactory implements InterceptorFactory { private final ByteCodeInstrumentor instrumentor; private final TraceContext traceContext; - private final Class interceptorClass; + private final String interceptorClassName; private final Object[] providedArguments; private final ParameterExtractorFactory parameterExtractorFactory; private final String scopeName; - public DefaultInterceptorFactory(ByteCodeInstrumentor instrumentor, TraceContext traceContext, Class interceptorClass, Object[] providedArguments, ParameterExtractorFactory parameterExtractorFactory, String scopeName) { + public DefaultInterceptorFactory(ByteCodeInstrumentor instrumentor, TraceContext traceContext, String interceptorClassName, Object[] providedArguments, ParameterExtractorFactory parameterExtractorFactory, String scopeName) { this.instrumentor = instrumentor; this.traceContext = traceContext; - this.interceptorClass = interceptorClass; + this.interceptorClassName = interceptorClassName; this.providedArguments = providedArguments == null ? NO_ARGS : providedArguments; this.parameterExtractorFactory = parameterExtractorFactory; this.scopeName = scopeName; @@ -40,7 +40,7 @@ public class DefaultInterceptorFactory implements InterceptorFactory { @Override public Interceptor getInterceptor(ClassLoader classLoader, InstrumentClass target, MethodInfo targetMethod) { - Interceptor interceptor = createInstance(traceContext, classLoader, target, targetMethod); + Interceptor interceptor = createInstance(classLoader, traceContext, target, targetMethod); if (scopeName != null) { interceptor = wrapWithScope(interceptor); @@ -48,8 +48,16 @@ public class DefaultInterceptorFactory implements InterceptorFactory { return interceptor; } - - private Interceptor createInstance(TraceContext traceContext, ClassLoader classLoader, InstrumentClass target, MethodInfo targetMethod) { + + private Interceptor createInstance(ClassLoader classLoader, TraceContext traceContext, InstrumentClass target, MethodInfo targetMethod) { + Class interceptorClass; + + try { + interceptorClass = classLoader.loadClass(interceptorClassName); + } catch (ClassNotFoundException e) { + throw new PinpointException("Cannot load interceptor class: " + interceptorClassName, e); + } + Constructor[] constructors = interceptorClass.getConstructors(); Arrays.sort(constructors, CONSTRUCTOR_COMPARATOR); diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultMetadataInjector.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultMetadataInjector.java index 919632ec0..f3d16c6ca 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultMetadataInjector.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultMetadataInjector.java @@ -4,27 +4,42 @@ import com.nhn.pinpoint.bootstrap.instrument.InstrumentClass; import com.nhn.pinpoint.bootstrap.instrument.InstrumentException; import com.nhn.pinpoint.bootstrap.interceptor.tracevalue.TraceValue; import com.nhn.pinpoint.bootstrap.plugin.MetadataInitializationStrategy.ByConstructor; +import com.nhn.pinpoint.exception.PinpointException; public class DefaultMetadataInjector implements MetadataInjector { - private final Class metadataType; + private final String metadataAccessorTypeName; private final MetadataInitializationStrategy strategy; - public DefaultMetadataInjector(Class metadataType, MetadataInitializationStrategy strategy) { - this.metadataType = metadataType; + public DefaultMetadataInjector(String metadataAccessorTypeName, MetadataInitializationStrategy strategy) { + this.metadataAccessorTypeName = metadataAccessorTypeName; this.strategy = strategy; } + @SuppressWarnings("unchecked") @Override public void inject(ClassLoader classLoader, InstrumentClass target) throws InstrumentException { + Class type; + try { + type = classLoader.loadClass(metadataAccessorTypeName); + } catch (ClassNotFoundException e) { + throw new PinpointException("Fail to load metadata accessor: " + metadataAccessorTypeName, e); + } + + if (!TraceValue.class.isAssignableFrom(type)) { + throw new PinpointException("Given type " + metadataAccessorTypeName + " is not a subtype of TraceValue"); + } + + Class metadataAccessorType = (Class)type; + if (strategy == null) { - target.addTraceValue(metadataType); + target.addTraceValue(metadataAccessorType); } else { if (strategy instanceof ByConstructor) { String javaExpression = "new " + ((ByConstructor)strategy).getClassName() + "();"; - target.addTraceValue(metadataType, javaExpression); + target.addTraceValue(metadataAccessorType, javaExpression); } else { - throw new IllegalArgumentException("Unsupported strategy: " + strategy); + throw new PinpointException("Unsupported strategy: " + strategy); } } } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPlugin.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPlugin.java index 67af74da6..feca85f5f 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPlugin.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/ProfilerPlugin.java @@ -3,5 +3,5 @@ package com.nhn.pinpoint.bootstrap.plugin; import java.util.List; public interface ProfilerPlugin { - public List getClassEditorMappings(ProfilerPluginContext context); + public List getClassEditors(ProfilerPluginContext context); } diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/interceptor/SpanSimpleAroundInterceptorTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/interceptor/SpanSimpleAroundInterceptorTest.java index 00f074d2f..70af937e8 100644 --- a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/interceptor/SpanSimpleAroundInterceptorTest.java +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/interceptor/SpanSimpleAroundInterceptorTest.java @@ -1,13 +1,14 @@ package com.nhn.pinpoint.bootstrap.interceptor; -import com.nhn.pinpoint.bootstrap.context.RecordableTrace; -import com.nhn.pinpoint.bootstrap.context.Trace; +import static org.mockito.Mockito.*; import junit.framework.Assert; + import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.mockito.Mockito.*; +import com.nhn.pinpoint.bootstrap.context.RecordableTrace; +import com.nhn.pinpoint.bootstrap.context.Trace; public class SpanSimpleAroundInterceptorTest { diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/ClassEditorBuilderTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/ClassEditorBuilderTest.java index c4480d12f..dd4dd00cf 100644 --- a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/ClassEditorBuilderTest.java +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/ClassEditorBuilderTest.java @@ -40,8 +40,8 @@ public class ClassEditorBuilderTest { ProfilerPluginContext helper = new ProfilerPluginContext(instrumentor, traceContext); ClassEditorBuilder builder = helper.newClassEditorBuilder(); - builder.intercept(methodName, parameterTypes).with(TestInterceptor.class).constructedWith("provided").in(scopeName); - builder.inject(TestMetadata.class).initializeWithDefaultConstructorOf("java.util.HashMap"); + builder.intercept(methodName, parameterTypeNames).with("com.nhn.pinpoint.bootstrap.plugin.TestInterceptor").constructedWith("provided").in(scopeName); + builder.inject("com.nhn.pinpoint.bootstrap.plugin.ClassEditorBuilderTest.TestMetadata").initializeWithDefaultConstructorOf("java.util.HashMap"); ClassEditor editor = builder.build(); editor.edit(classLoader, aClass); diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultInterceptorFactoryTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultInterceptorFactoryTest.java index a98795b82..c2d701770 100644 --- a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultInterceptorFactoryTest.java +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/DefaultInterceptorFactoryTest.java @@ -39,7 +39,7 @@ public class DefaultInterceptorFactoryTest { @Test public void test0() throws Exception { - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor0.class, null, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor0", null, null, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor0.class, interceptor.getClass()); @@ -49,7 +49,7 @@ public class DefaultInterceptorFactoryTest { public void test1() throws Exception { Object[] args = new Object[] { "arg0" }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor0.class, args, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor0", args, null, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor0.class, interceptor.getClass()); @@ -60,7 +60,7 @@ public class DefaultInterceptorFactoryTest { public void test2() throws Exception { Object[] args = new Object[] { 1 }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor0.class, args, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor0", args, null, null); factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); } @@ -68,7 +68,7 @@ public class DefaultInterceptorFactoryTest { public void test3() throws Exception { Object[] args = new Object[] { "arg0", (byte)1, (short)2, (float)3.0 }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor1.class, args, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor1", args, null, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor1.class, interceptor.getClass()); @@ -82,7 +82,7 @@ public class DefaultInterceptorFactoryTest { public void test4() throws Exception { Object[] args = new Object[] { (byte)1, (short)2, (float)3.0, "arg0" }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor1.class, args, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor1", args, null, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor1.class, interceptor.getClass()); @@ -96,7 +96,7 @@ public class DefaultInterceptorFactoryTest { public void test5() throws Exception { Object[] args = new Object[] { (short)2, (float)3.0, "arg0", (byte)1 }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor1.class, args, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor1", args, null, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor1.class, interceptor.getClass()); @@ -110,7 +110,7 @@ public class DefaultInterceptorFactoryTest { public void test6() throws Exception { Object[] args = new Object[] { (float)3.0, (short)2, (byte)1, "arg0" }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor1.class, args, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor1", args, null, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor1.class, interceptor.getClass()); @@ -124,13 +124,13 @@ public class DefaultInterceptorFactoryTest { public void test7() throws Exception { Object[] args = new Object[] { (double)3.0, (short)2, (byte)1, "arg0" }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor1.class, args, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor1", args, null, null); factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); } @Test(expected=PinpointException.class) public void test8() throws Exception { - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor1.class, null, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor1", null, null, null); factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); } @@ -138,7 +138,7 @@ public class DefaultInterceptorFactoryTest { public void test9() throws Exception { Object[] args = new Object[] { "arg0", 1, 2.0, true, 3L }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor2.class, args, extractorFactory, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor2", args, extractorFactory, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor2.class, interceptor.getClass()); @@ -156,7 +156,7 @@ public class DefaultInterceptorFactoryTest { public void test10() throws Exception { Object[] args = new Object[] { "arg0", 1, 2.0 }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor2.class, args, extractorFactory, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor2", args, extractorFactory, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor2.class, interceptor.getClass()); @@ -174,7 +174,7 @@ public class DefaultInterceptorFactoryTest { public void test11() throws Exception { Object[] args = new Object[] { "arg0", 1 }; - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor2.class, args, extractorFactory, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor2", args, extractorFactory, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor2.class, interceptor.getClass()); @@ -190,7 +190,7 @@ public class DefaultInterceptorFactoryTest { @Test public void test12() throws Exception { - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor2.class, null, extractorFactory, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor2", null, extractorFactory, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor2.class, interceptor.getClass()); @@ -206,7 +206,7 @@ public class DefaultInterceptorFactoryTest { @Test public void test13() throws Exception { - DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, TestInterceptor2.class, null, null, null); + DefaultInterceptorFactory factory = new DefaultInterceptorFactory(instrumentor, traceContext, "com.nhn.pinpoint.bootstrap.plugin.TestInterceptors.TestInterceptor2", null, null, null); Interceptor interceptor = factory.getInterceptor(getClass().getClassLoader(), aClass, aMethod); assertEquals(TestInterceptor2.class, interceptor.getClass()); diff --git a/plugins/.gitignore b/plugins/.gitignore deleted file mode 100644 index 0c2b833ee..000000000 --- a/plugins/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/.settings/ -/.project diff --git a/plugins/pom.xml b/plugins/pom.xml deleted file mode 100644 index 103d548b0..000000000 --- a/plugins/pom.xml +++ /dev/null @@ -1,22 +0,0 @@ - - 4.0.0 - - com.nhn.pinpoint - pom - 1.0.4-SNAPSHOT - - - pinpoint-plugins - pinpoint-plugins - pom - - - arcus - - - - - - - diff --git a/pom.xml b/pom.xml index 5a8b2cc3c..ecaa4df2a 100644 --- a/pom.xml +++ b/pom.xml @@ -68,13 +68,20 @@ profiler profiler-optional rpc + test thrift web + + + arcus 1.0.4-SNAPSHOT - + + build/pinpoint-agent + ${pinpoint.agent.directory}/plugin + UTF-8 1.6 1.7.5 @@ -668,19 +675,6 @@ maven-antrun-plugin 1.7 - - com.nhncorp.maven - maven-revision-plugin - 1.0.0 - - - compile - - create - - - - org.apache.maven.plugins maven-surefire-plugin @@ -724,7 +718,7 @@ maven-klocwork-plugin 1.0.0 - + diff --git a/profiler/pom.xml b/profiler/pom.xml index 7117ffbff..72f15c128 100644 --- a/profiler/pom.xml +++ b/profiler/pom.xml @@ -12,7 +12,7 @@ jar - ${basedir}/target/pinpoint-agent/ + ../${pinpoint.agent.directory} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/ClassFileTransformerDispatcher.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/ClassFileTransformerDispatcher.java index 4648533e1..a41f45bad 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/ClassFileTransformerDispatcher.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/ClassFileTransformerDispatcher.java @@ -11,7 +11,8 @@ import org.slf4j.LoggerFactory; import com.nhn.pinpoint.bootstrap.config.ProfilerConfig; import com.nhn.pinpoint.bootstrap.instrument.ByteCodeInstrumentor; -import com.nhn.pinpoint.bootstrap.plugin.ClassEditorFactoryMapping; +import com.nhn.pinpoint.bootstrap.plugin.ClassEditor; +import com.nhn.pinpoint.bootstrap.plugin.DedicatedClassEditor; import com.nhn.pinpoint.bootstrap.plugin.PluginClassLoaderFactory; import com.nhn.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.nhn.pinpoint.bootstrap.plugin.ProfilerPluginContext; @@ -63,13 +64,22 @@ public class ClassFileTransformerDispatcher implements ClassFileTransformer { @Override public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classFileBuffer) throws IllegalClassFormatException { - + if (className.contains("CacheManager")) { + logger.debug("Start CacheManager"); + } + if (skipFilter.doFilter(classLoader, className, classBeingRedefined, protectionDomain, classFileBuffer)) { + if (className.equals("net/spy/memcached/CacheManager")) { + logger.debug("skip CacheManager"); + } return null; } AbstractModifier findModifier = this.modifierRegistry.findModifier(className); if (findModifier == null) { + if (className.equals("net/spy/memcached/CacheManager")) { + logger.debug("no modifier for CacheManager"); + } // TODO : 디버그 용도로 추가함 // TODO : modifier가 중복 적용되면 어떻게 되지??? if (this.profilerConfig.getProfilableClassFilter().filter(className)) { @@ -171,8 +181,16 @@ public class ClassFileTransformerDispatcher implements ClassFileTransformer { ProfilerPluginContext pluginContext = new ProfilerPluginContext(byteCodeInstrumentor, agent.getTraceContext()); for (ProfilerPlugin plugin : plugins) { - for (ClassEditorFactoryMapping mapping : plugin.getClassEditorMappings(pluginContext)) { - modifierRepository.addModifier(new ClassEditorAdaptor(byteCodeInstrumentor, agent, mapping, pluginContext, classLoaderFactory)); + logger.info("Loading plugin: {}", plugin.getClass().getName()); + + for (ClassEditor editor : plugin.getClassEditors(pluginContext)) { + if (editor instanceof DedicatedClassEditor) { + DedicatedClassEditor dedicated = (DedicatedClassEditor)editor; + logger.info("Registering class editor {} for {} ", dedicated.getClass().getName(), dedicated.getTargetClassName()); + modifierRepository.addModifier(new ClassEditorAdaptor(byteCodeInstrumentor, agent, dedicated, classLoaderFactory)); + } else { + logger.warn("Ignore class editor {}", editor.getClass().getName()); + } } } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java index bae81deda..8e11b9704 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java @@ -115,12 +115,6 @@ public class DefaultAgent implements Agent { logger.info("DefaultAgent classLoader:{}", this.getClass().getClassLoader()); } - ClassFileRetransformer retransformer = new ClassFileRetransformer(instrumentation); - instrumentation.addTransformer(retransformer, true); - this.classFileTransformer = new ClassFileTransformerDispatcher(this, byteCodeInstrumentor, retransformer); - instrumentation.addTransformer(this.classFileTransformer); - - final AgentInformationFactory agentInformationFactory = new AgentInformationFactory(); this.agentInformation = agentInformationFactory.createAgentInformation(typeResolver.getServerType()); logger.info("agentInformation:{}", agentInformation); @@ -145,6 +139,13 @@ public class DefaultAgent implements Agent { // JVM 통계 등을 주기적으로 수집하여 collector에 전송하는 monitor를 초기화한다. this.agentStatMonitor = new AgentStatMonitor(this.statDataSender, this.agentInformation.getAgentId(), this.agentInformation.getStartTime()); + + + ClassFileRetransformer retransformer = new ClassFileRetransformer(instrumentation); + instrumentation.addTransformer(retransformer, true); + this.classFileTransformer = new ClassFileTransformerDispatcher(this, byteCodeInstrumentor, retransformer); + instrumentation.addTransformer(this.classFileTransformer); + preLoadClass(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClass.java index b01a6f02d..d08ca8ea5 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClass.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/bci/JavaAssistClass.java @@ -5,13 +5,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import com.nhn.pinpoint.bootstrap.context.TraceContext; -import com.nhn.pinpoint.bootstrap.interceptor.*; import javassist.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.nhn.pinpoint.bootstrap.context.TraceContext; import com.nhn.pinpoint.bootstrap.instrument.InstrumentClass; import com.nhn.pinpoint.bootstrap.instrument.InstrumentException; import com.nhn.pinpoint.bootstrap.instrument.MethodFilter; @@ -19,6 +18,17 @@ import com.nhn.pinpoint.bootstrap.instrument.MethodInfo; import com.nhn.pinpoint.bootstrap.instrument.NotFoundInstrumentException; import com.nhn.pinpoint.bootstrap.instrument.Scope; import com.nhn.pinpoint.bootstrap.instrument.Type; +import com.nhn.pinpoint.bootstrap.interceptor.ByteCodeMethodDescriptorSupport; +import com.nhn.pinpoint.bootstrap.interceptor.Interceptor; +import com.nhn.pinpoint.bootstrap.interceptor.InterceptorRegistry; +import com.nhn.pinpoint.bootstrap.interceptor.LoggingInterceptor; +import com.nhn.pinpoint.bootstrap.interceptor.MethodDescriptor; +import com.nhn.pinpoint.bootstrap.interceptor.SimpleAfterInterceptor; +import com.nhn.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor; +import com.nhn.pinpoint.bootstrap.interceptor.SimpleBeforeInterceptor; +import com.nhn.pinpoint.bootstrap.interceptor.SimpleInterceptor; +import com.nhn.pinpoint.bootstrap.interceptor.StaticAroundInterceptor; +import com.nhn.pinpoint.bootstrap.interceptor.TraceContextSupport; import com.nhn.pinpoint.bootstrap.interceptor.tracevalue.TraceValue; import com.nhn.pinpoint.profiler.interceptor.DebugScopeDelegateSimpleInterceptor; import com.nhn.pinpoint.profiler.interceptor.DebugScopeDelegateStaticInterceptor; @@ -283,16 +293,17 @@ public class JavaAssistClass implements InstrumentClass { throw new IllegalArgumentException("interceptor is null"); } final CtConstructor behavior = getCtConstructor(args); - return addInterceptor0(behavior, null, interceptor, NOT_DEFINE_INTERCEPTOR_ID, Type.around, false); + return addInterceptor0(behavior, null, interceptor, NOT_DEFINE_INTERCEPTOR_ID, false); } @Override + // TODO remove parameter type public int addConstructorInterceptor(String[] args, Interceptor interceptor, Type type) throws InstrumentException, NotFoundInstrumentException { if (interceptor == null) { throw new IllegalArgumentException("interceptor is null"); } final CtConstructor behavior = getCtConstructor(args); - return addInterceptor0(behavior, null, interceptor, NOT_DEFINE_INTERCEPTOR_ID, type, false); + return addInterceptor0(behavior, null, interceptor, NOT_DEFINE_INTERCEPTOR_ID, false); } @Override @@ -301,6 +312,7 @@ public class JavaAssistClass implements InstrumentClass { } @Override + // TODO remove parameter type public int addAllConstructorInterceptor(Interceptor interceptor, Type type) throws InstrumentException, NotFoundInstrumentException { if (interceptor == null) { throw new IllegalArgumentException("interceptor is null"); @@ -312,11 +324,11 @@ public class JavaAssistClass implements InstrumentClass { } int interceptorId = 0; if (length > 0) { - interceptorId = addInterceptor0(constructorList[0], null, interceptor, NOT_DEFINE_INTERCEPTOR_ID, type, false); + interceptorId = addInterceptor0(constructorList[0], null, interceptor, NOT_DEFINE_INTERCEPTOR_ID, false); } if (length > 1) { for (int i = 1; i< length; i++) { - addInterceptor0(constructorList[i], null, null, interceptorId, Type.around, false); + addInterceptor0(constructorList[i], null, null, interceptorId, false); } } return interceptorId; @@ -329,16 +341,17 @@ public class JavaAssistClass implements InstrumentClass { throw new IllegalArgumentException("interceptor is null"); } final CtBehavior behavior = getMethod(methodName, args); - return addInterceptor0(behavior, methodName, interceptor, NOT_DEFINE_INTERCEPTOR_ID, Type.around, true); + return addInterceptor0(behavior, methodName, interceptor, NOT_DEFINE_INTERCEPTOR_ID, true); } @Override + // TODO remove parameter type public int addInterceptorCallByContextClassLoader(String methodName, String[] args, Interceptor interceptor, Type type) throws InstrumentException, NotFoundInstrumentException { if (interceptor == null) { throw new IllegalArgumentException("interceptor is null"); } final CtBehavior behavior = getMethod(methodName, args); - return addInterceptor0(behavior, methodName, interceptor, NOT_DEFINE_INTERCEPTOR_ID, type, true); + return addInterceptor0(behavior, methodName, interceptor, NOT_DEFINE_INTERCEPTOR_ID, true); } @Override @@ -350,7 +363,7 @@ public class JavaAssistClass implements InstrumentClass { throw new IllegalArgumentException("interceptor is null"); } final CtBehavior behavior = getMethod(methodName, args); - return addInterceptor0(behavior, methodName, interceptor, NOT_DEFINE_INTERCEPTOR_ID, Type.around, false); + return addInterceptor0(behavior, methodName, interceptor, NOT_DEFINE_INTERCEPTOR_ID, false); } @Override @@ -431,33 +444,35 @@ public class JavaAssistClass implements InstrumentClass { @Override public int reuseInterceptor(String methodName, String[] args, int interceptorId) throws InstrumentException, NotFoundInstrumentException { final CtBehavior behavior = getMethod(methodName, args); - return addInterceptor0(behavior, methodName, null, interceptorId, Type.around, false); + return addInterceptor0(behavior, methodName, null, interceptorId, false); } @Override + // TODO remove parameter type public int reuseInterceptor(String methodName, String[] args, int interceptorId, Type type) throws InstrumentException, NotFoundInstrumentException { final CtBehavior behavior = getMethod(methodName, args); - return addInterceptor0(behavior, methodName, null, interceptorId, type, false); + return addInterceptor0(behavior, methodName, null, interceptorId, false); } @Override + // TODO remove parameter type public int addInterceptor(String methodName, String[] args, Interceptor interceptor, Type type) throws InstrumentException, NotFoundInstrumentException { if (interceptor == null) { throw new IllegalArgumentException("interceptor is null"); } final CtBehavior behavior = getMethod(methodName, args); - return addInterceptor0(behavior, methodName, interceptor, NOT_DEFINE_INTERCEPTOR_ID, type, false); + return addInterceptor0(behavior, methodName, interceptor, NOT_DEFINE_INTERCEPTOR_ID, false); } - private int addInterceptor0(CtBehavior behavior, String methodName, Interceptor interceptor, int interceptorId, Type type, boolean useContextClassLoader) throws InstrumentException, NotFoundInstrumentException { + private int addInterceptor0(CtBehavior behavior, String methodName, Interceptor interceptor, int interceptorId, boolean useContextClassLoader) throws InstrumentException, NotFoundInstrumentException { try { if (interceptor != null) { if(interceptor instanceof StaticAroundInterceptor) { StaticAroundInterceptor staticAroundInterceptor = (StaticAroundInterceptor) interceptor; interceptorId = InterceptorRegistry.addInterceptor(staticAroundInterceptor); - } else if(interceptor instanceof SimpleAroundInterceptor) { - SimpleAroundInterceptor simpleAroundInterceptor = (SimpleAroundInterceptor) interceptor; + } else if(interceptor instanceof SimpleInterceptor) { + SimpleInterceptor simpleAroundInterceptor = (SimpleInterceptor) interceptor; interceptorId = InterceptorRegistry.addSimpleInterceptor(simpleAroundInterceptor); } else { throw new InstrumentException("unsupported Interceptor Type:" + interceptor); @@ -469,32 +484,28 @@ public class JavaAssistClass implements InstrumentClass { } // 이제는 aroundType 인터셉터만 받고 코드 인젝션을 별도 type으로 받아야 함. if (interceptor instanceof StaticAroundInterceptor) { - switch (type) { - case around: +// switch (type) { +// case around: addStaticAroundInterceptor(methodName, interceptorId, behavior, useContextClassLoader); - break; - case before: - addStaticBeforeInterceptor(methodName, interceptorId, behavior, useContextClassLoader); - break; - case after: - addStaticAfterInterceptor(methodName, interceptorId, behavior, useContextClassLoader); - break; - default: - throw new UnsupportedOperationException("unsupport type"); - } - } else if(interceptor instanceof SimpleAroundInterceptor) { - switch (type) { - case around: - addSimpleAroundInterceptor(methodName, interceptorId, behavior, useContextClassLoader); - break; - case before: - addSimpleBeforeInterceptor(methodName, interceptorId, behavior, useContextClassLoader); - break; - case after: - addSimpleAfterInterceptor(methodName, interceptorId, behavior, useContextClassLoader); - break; - default: - throw new UnsupportedOperationException("unsupport type"); +// break; +// case before: +// addStaticBeforeInterceptor(methodName, interceptorId, behavior, useContextClassLoader); +// break; +// case after: +// addStaticAfterInterceptor(methodName, interceptorId, behavior, useContextClassLoader); +// break; +// default: +// throw new UnsupportedOperationException("unsupport type"); +// } + } else if(interceptor instanceof SimpleInterceptor) { + if (interceptor instanceof SimpleAroundInterceptor) { + addSimpleAroundInterceptor(methodName, interceptorId, behavior, useContextClassLoader); + } else if (interceptor instanceof SimpleBeforeInterceptor) { + addSimpleBeforeInterceptor(methodName, interceptorId, behavior, useContextClassLoader); + } else if (interceptor instanceof SimpleAfterInterceptor) { + addSimpleAfterInterceptor(methodName, interceptorId, behavior, useContextClassLoader); + } else { + throw new UnsupportedOperationException("unsupport type"); } } else { throw new IllegalArgumentException("unsupported"); @@ -629,7 +640,7 @@ public class JavaAssistClass implements InstrumentClass { after.format(" %1$s interceptor = com.nhn.pinpoint.bootstrap.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticAroundInterceptor.class.getName(), id); after.format(" interceptor.after(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, %6$s, null);", target, ctClass.getName(), methodName, parameterTypeString, parameterIdentifier, returnType); } else { - after.format(" %1$s interceptor = com.nhn.pinpoint.bootstrap.interceptor.InterceptorRegistry.getSimpleInterceptor(%2$d);", SimpleAroundInterceptor.class.getName(), id); + after.format(" %1$s interceptor = (%1$s)com.nhn.pinpoint.bootstrap.interceptor.InterceptorRegistry.getSimpleInterceptor(%2$d);", SimpleAroundInterceptor.class.getName(), id); after.format(" interceptor.after(%1$s, %2$s, %3$s, null);", target, parameterIdentifier, returnType); } after.end(); @@ -765,14 +776,14 @@ public class JavaAssistClass implements InstrumentClass { code.format(" interceptor.before(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s);", target, ctClass.getName(), methodName, parameterDescription, parameterIdentifier); } else { // simpleInterceptor인덱스에서 검색하여 typecasting을 제거한다. - code.format(" %1$s interceptor = com.nhn.pinpoint.bootstrap.interceptor.InterceptorRegistry.getSimpleInterceptor(%2$d);", SimpleAroundInterceptor.class.getName(), id); + code.format(" %1$s interceptor = (%1$s)com.nhn.pinpoint.bootstrap.interceptor.InterceptorRegistry.getSimpleInterceptor(%2$d);", SimpleBeforeInterceptor.class.getName(), id); code.format(" interceptor.before(%1$s, %2$s);", target, parameterIdentifier); } code.end(); } String buildBefore = code.toString(); if (isDebug) { - logger.debug("addStaticBeforeInterceptor catch behavior:{} code:{}", behavior.getLongName(), buildBefore); + logger.debug("addBeforeInterceptor catch behavior:{} code:{}", behavior.getLongName(), buildBefore); } if (behavior instanceof CtConstructor) { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassEditorAdaptor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassEditorAdaptor.java index 59d12eb1d..9a7994daa 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassEditorAdaptor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassEditorAdaptor.java @@ -2,52 +2,47 @@ package com.nhn.pinpoint.profiler.plugin; import java.security.ProtectionDomain; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.nhn.pinpoint.bootstrap.Agent; import com.nhn.pinpoint.bootstrap.instrument.ByteCodeInstrumentor; import com.nhn.pinpoint.bootstrap.instrument.InstrumentClass; -import com.nhn.pinpoint.bootstrap.plugin.ClassEditor; -import com.nhn.pinpoint.bootstrap.plugin.ClassEditorFactory; -import com.nhn.pinpoint.bootstrap.plugin.ClassEditorFactoryMapping; +import com.nhn.pinpoint.bootstrap.plugin.DedicatedClassEditor; import com.nhn.pinpoint.bootstrap.plugin.PluginClassLoaderFactory; -import com.nhn.pinpoint.bootstrap.plugin.ProfilerPluginContext; import com.nhn.pinpoint.exception.PinpointException; import com.nhn.pinpoint.profiler.modifier.AbstractModifier; public class ClassEditorAdaptor extends AbstractModifier { - private final ClassEditorFactoryMapping mapping; - private final ProfilerPluginContext pluginContext; + private final Logger logger = LoggerFactory.getLogger(getClass()); + private final DedicatedClassEditor editor; private final PluginClassLoaderFactory classLoaderFactory; - public ClassEditorAdaptor(ByteCodeInstrumentor byteCodeInstrumentor, Agent agent, ClassEditorFactoryMapping mapping, ProfilerPluginContext pluginContext, PluginClassLoaderFactory classLoaderFactory) { + public ClassEditorAdaptor(ByteCodeInstrumentor byteCodeInstrumentor, Agent agent, DedicatedClassEditor editor, PluginClassLoaderFactory classLoaderFactory) { super(byteCodeInstrumentor, agent); - this.mapping = mapping; - this.pluginContext = pluginContext; + this.editor = editor; this.classLoaderFactory = classLoaderFactory; } @Override public byte[] modify(ClassLoader classLoader, String className, ProtectionDomain protectionDomain, byte[] classFileBuffer) { + logger.debug("Editing class {}", className); + ClassLoader forPlugin = classLoaderFactory.get(classLoader); ClassLoader old = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(forPlugin); try { - Class editorFactoryClass = forPlugin.loadClass(mapping.getEditorFactoryClassName()); - - if (!ClassEditorFactory.class.isAssignableFrom(editorFactoryClass)) { - throw new PinpointException("Illegal class editor factory mapping. factory class[" + editorFactoryClass + "] did not implent ClassEditorFactory"); - } - - ClassEditorFactory editorFactory = (ClassEditorFactory)editorFactoryClass.newInstance(); - ClassEditor editor = editorFactory.get(pluginContext); - InstrumentClass target = byteCodeInstrumentor.getClass(classLoader, className, classFileBuffer); - return editor.edit(classLoader, target); + } catch (PinpointException e) { + throw e; } catch (Exception e) { - throw new PinpointException("Fail to invoke plugin class editor for " + mapping.getTargetClassName() + ", editor factory: " + mapping.getEditorFactoryClassName(), e); + String msg = "Fail to invoke plugin class editor " + editor.getClass().getName() + " for " + editor.getTargetClassName(); + logger.warn(msg, e); + throw new PinpointException(msg, e); } finally { Thread.currentThread().setContextClassLoader(old); } @@ -56,6 +51,6 @@ public class ClassEditorAdaptor extends AbstractModifier { @Override public String getTargetClass() { - return mapping.getTargetClassName(); + return editor.getTargetClassName().replace('.', '/'); } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/ForkedJUnit.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/ForkedJUnit.java new file mode 100644 index 000000000..b98b26ce9 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/ForkedJUnit.java @@ -0,0 +1,100 @@ +package com.nhn.pinpoint.profiler.util; + +import java.util.regex.Pattern; + +import org.junit.runner.Description; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +public class ForkedJUnit { + static final String JUNIT_OUTPUT_DELIMETER = "#####"; + static final String JUNIT_OUTPUT_DELIMETER_REGEXP = Pattern.quote(JUNIT_OUTPUT_DELIMETER); + private static boolean forked = false; + + public static boolean isForked() { + return forked; + } + + + public static void main(String[] args) throws ClassNotFoundException { + forked = true; + + Class[] classes = new Class[args.length]; + + for (int i = 0; i < args.length; i++) { + classes[i] = Class.forName(args[i]); + } + + JUnitCore junit = new JUnitCore(); + junit.addListener(new PrintListener()); + Result result = junit.run(classes); + + System.exit(result.getFailureCount()); + } + + private static class PrintListener extends RunListener { + + @Override + public void testRunStarted(Description description) throws Exception { + System.out.println(JUNIT_OUTPUT_DELIMETER + "testRunStarted"); + } + + @Override + public void testRunFinished(Result result) throws Exception { + System.out.println(JUNIT_OUTPUT_DELIMETER + "testRunFinished"); + } + + @Override + public void testStarted(Description description) throws Exception { + System.out.println(JUNIT_OUTPUT_DELIMETER + "testStarted" + JUNIT_OUTPUT_DELIMETER + description.getDisplayName()); + } + + @Override + public void testFinished(Description description) throws Exception { + System.out.println(JUNIT_OUTPUT_DELIMETER + "testFinished" + JUNIT_OUTPUT_DELIMETER + description.getDisplayName()); + } + + @Override + public void testFailure(Failure failure) throws Exception { + System.out.println(JUNIT_OUTPUT_DELIMETER + "testFailure" + JUNIT_OUTPUT_DELIMETER + failureToString(failure)); + } + + @Override + public void testAssumptionFailure(Failure failure) { + System.out.println(JUNIT_OUTPUT_DELIMETER + "testAssumptionFailure" + JUNIT_OUTPUT_DELIMETER + failureToString(failure)); + } + + @Override + public void testIgnored(Description description) throws Exception { + System.out.println(JUNIT_OUTPUT_DELIMETER + "testIgnored" + JUNIT_OUTPUT_DELIMETER + description.getDisplayName()); + } + + private String failureToString(Failure failure) { + StringBuilder builder = new StringBuilder(); + + builder.append(failure.getTestHeader()); + builder.append(JUNIT_OUTPUT_DELIMETER); + builder.append(failure.getException().getClass().getName()); + builder.append(JUNIT_OUTPUT_DELIMETER); + builder.append(failure.getMessage()); + builder.append(JUNIT_OUTPUT_DELIMETER); + + for (StackTraceElement e : failure.getException().getStackTrace()) { + builder.append(e.getClassName()); + builder.append(','); + builder.append(e.getMethodName()); + builder.append(','); + builder.append(e.getFileName()); + builder.append(','); + builder.append(e.getLineNumber()); + + builder.append(JUNIT_OUTPUT_DELIMETER); + } + + return builder.toString(); + } + } + +} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/PinpointAgent.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/PinpointAgent.java new file mode 100644 index 000000000..7fc6da228 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/PinpointAgent.java @@ -0,0 +1,12 @@ +package com.nhn.pinpoint.profiler.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface PinpointAgent { + String value(); +} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/PinpointConfig.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/PinpointConfig.java new file mode 100644 index 000000000..df5d6d208 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/PinpointConfig.java @@ -0,0 +1,12 @@ +package com.nhn.pinpoint.profiler.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface PinpointConfig { + String value(); +} diff --git a/test/pom.xml b/test/pom.xml index ff8171bce..91dfc8865 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -8,7 +8,7 @@ pinpoint-test - pinpoint test helper libraries + pinpoint test helper jar @@ -16,6 +16,12 @@ com.nhn.pinpoint pinpoint-profiler + + + junit + junit + compile + diff --git a/test/src/main/java/com/nhn/pinpoint/test/fork/ExcludeLibraries.java b/test/src/main/java/com/nhn/pinpoint/test/fork/ExcludeLibraries.java new file mode 100644 index 000000000..aa0b54156 --- /dev/null +++ b/test/src/main/java/com/nhn/pinpoint/test/fork/ExcludeLibraries.java @@ -0,0 +1,12 @@ +package com.nhn.pinpoint.test.fork; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ExcludeLibraries { + String[] value() default {}; +} diff --git a/test/src/main/java/com/nhn/pinpoint/test/fork/ForkRunner.java b/test/src/main/java/com/nhn/pinpoint/test/fork/ForkRunner.java index 7427c0d21..371b10f58 100644 --- a/test/src/main/java/com/nhn/pinpoint/test/fork/ForkRunner.java +++ b/test/src/main/java/com/nhn/pinpoint/test/fork/ForkRunner.java @@ -1,7 +1,9 @@ -package com.nhn.pinpoint.profiler.util; +package com.nhn.pinpoint.test.fork; import java.io.File; import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -20,19 +22,24 @@ import org.junit.runners.model.Statement; import com.nhn.pinpoint.common.Version; public class ForkRunner extends BlockJUnit4ClassRunner { + private static final String[] REQUIRED_CLASS_PATHS = new String[] { + "junit", + "pinpoint-test", + "pinpoint/test" + }; + private final String agentJar; private final String configPath; + private final boolean testOnChildClassLoader; + private final String[] excludedLibraries; + private final String[] includedLibraries; public ForkRunner(Class klass) throws InitializationError { super(klass); - PinpointAgent path = klass.getAnnotation(PinpointAgent.class); - - if (path != null && path.value() != null) { - agentJar = path.value(); - } else { - agentJar = "target/pinpoint-agent/pinpoint-bootstrap-" + Version.VERSION + ".jar"; - } + PinpointAgentPath path = klass.getAnnotation(PinpointAgentPath.class); + String agentPath = (path != null && path.value() != null) ? path.value() : "target/pinpoint-agent"; + agentJar = agentPath + "/pinpoint-bootstrap-" + Version.VERSION + ".jar"; PinpointConfig config = klass.getAnnotation(PinpointConfig.class); @@ -41,6 +48,14 @@ public class ForkRunner extends BlockJUnit4ClassRunner { } else { configPath = null; } + + testOnChildClassLoader = klass.isAnnotationPresent(OnChildClassLoader.class); + + ExcludeLibraries exclude = klass.getAnnotation(ExcludeLibraries.class); + excludedLibraries = exclude == null ? new String[0] : exclude.value(); + + WithLibraries include = klass.getAnnotation(WithLibraries.class); + includedLibraries = include == null ? new String[0] : include.value(); } @Override @@ -67,6 +82,9 @@ public class ForkRunner extends BlockJUnit4ClassRunner { builder.command(buildCommand()); builder.redirectErrorStream(true); + + System.out.println("Working directory: " + System.getProperty("user.dir")); + System.out.println("Command: " + builder.command()); Process process; try { @@ -120,26 +138,44 @@ public class ForkRunner extends BlockJUnit4ClassRunner { } } - private String[] buildCommand() { + private String[] buildCommand() throws URISyntaxException { List list = new ArrayList(); list.add(getJavaExecutable()); list.add("-cp"); list.add(getClassPath()); list.add(getAgent()); + list.add("-Dpinpoint.agentId=build.test.0"); list.add("-Dpinpoint.applicationName=test"); + + if (isDebugMode()) { + list.addAll(getDebugOptions()); + } if (configPath != null) { list.add("-Dpinpoint.config=" + configPath); } list.add(ForkedJUnit.class.getName()); + + if (testOnChildClassLoader) { + list.add(getChildClassPath()); + } + list.add(getTestClass().getName()); return list.toArray(new String[list.size()]); } - + + private boolean isDebugMode() { + return ManagementFactory.getRuntimeMXBean().getInputArguments().toString().contains("jdwp"); + } + + private List getDebugOptions() { + return Arrays.asList("-Xdebug", "-agentlib:jdwp=transport=dt_socket,address=1296,server=y,suspend=y"); + } + private String getAgent() { return "-javaagent:" + agentJar; } @@ -159,19 +195,63 @@ public class ForkRunner extends BlockJUnit4ClassRunner { return builder.toString(); } - - private String getClassPath() { - URLClassLoader cl = (URLClassLoader) ClassLoader.getSystemClassLoader(); + + private String getClassPath() throws URISyntaxException { StringBuilder classPath = new StringBuilder(); - for (URL url : cl.getURLs()) { - classPath.append(url.getPath()); - classPath.append(File.pathSeparatorChar); + if (testOnChildClassLoader) { + URLClassLoader cl = (URLClassLoader) ClassLoader.getSystemClassLoader(); + + outer: + for (URL url : cl.getURLs()) { + for (String required : REQUIRED_CLASS_PATHS) { + if (url.getFile().contains(required)) { + classPath.append(new File(url.toURI()).getAbsolutePath()); + classPath.append(File.pathSeparatorChar); + continue outer; + } + } + } + } else { + appendClassPath(classPath); } return classPath.toString(); } + + private void appendClassPath(StringBuilder classPath) throws URISyntaxException { + URLClassLoader cl = (URLClassLoader) ClassLoader.getSystemClassLoader(); + + outer: + for (URL url : cl.getURLs()) { + String urlAsString = url.toString(); + for (String exclude : excludedLibraries) { + if (urlAsString.contains(exclude)) { + continue outer; + } + } + + classPath.append(new File(url.toURI()).getAbsolutePath()); + classPath.append(File.pathSeparatorChar); + } + + for (String include : includedLibraries) { + classPath.append(include); + classPath.append(File.pathSeparatorChar); + } + + } + + private String getChildClassPath() throws URISyntaxException { + StringBuilder classPath = new StringBuilder(); + + classPath.append(ForkedJUnit.CHILD_CLASS_PATH_PREFIX); + appendClassPath(classPath); + + return classPath.toString(); + } + private Description findDescription(Description description, String displayName) { if (displayName.equals(description.getDisplayName())) { return description; @@ -201,7 +281,6 @@ public class ForkRunner extends BlockJUnit4ClassRunner { for (int i = 0; i < traceInText.size(); i++) { String trace = traceInText.get(i); - System.out.println(trace); String[] tokens = trace.split(","); stackTrace[i] = new StackTraceElement(tokens[0], tokens[1], tokens[2], Integer.valueOf(tokens[3])); diff --git a/test/src/main/java/com/nhn/pinpoint/test/fork/ForkedJUnit.java b/test/src/main/java/com/nhn/pinpoint/test/fork/ForkedJUnit.java index b98b26ce9..b3309fe2a 100644 --- a/test/src/main/java/com/nhn/pinpoint/test/fork/ForkedJUnit.java +++ b/test/src/main/java/com/nhn/pinpoint/test/fork/ForkedJUnit.java @@ -1,5 +1,12 @@ -package com.nhn.pinpoint.profiler.util; +package com.nhn.pinpoint.test.fork; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.regex.Pattern; import org.junit.runner.Description; @@ -9,6 +16,7 @@ import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunListener; public class ForkedJUnit { + static final String CHILD_CLASS_PATH_PREFIX = "-child="; static final String JUNIT_OUTPUT_DELIMETER = "#####"; static final String JUNIT_OUTPUT_DELIMETER_REGEXP = Pattern.quote(JUNIT_OUTPUT_DELIMETER); private static boolean forked = false; @@ -18,21 +26,61 @@ public class ForkedJUnit { } - public static void main(String[] args) throws ClassNotFoundException { + public static void main(String[] args) throws ClassNotFoundException, MalformedURLException { forked = true; - Class[] classes = new Class[args.length]; + int from = 0; + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); - for (int i = 0; i < args.length; i++) { - classes[i] = Class.forName(args[i]); + if (args[0].startsWith(CHILD_CLASS_PATH_PREFIX)) { + String jars = args[0].substring(CHILD_CLASS_PATH_PREFIX.length()); + List urls = getJarUrls(jars); + classLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), classLoader); + from = 1; } - JUnitCore junit = new JUnitCore(); - junit.addListener(new PrintListener()); - Result result = junit.run(classes); + List testClassNames = Arrays.asList(args).subList(from, args.length); + List> classes = loadTestClasses(classLoader, testClassNames); + + Result result = runTests(classes); System.exit(result.getFailureCount()); } + + + private static Result runTests(List> classes) { + JUnitCore junit = new JUnitCore(); + junit.addListener(new PrintListener()); + Result result = junit.run(classes.toArray(new Class[classes.size()])); + return result; + } + + + private static List getJarUrls(String jars) throws MalformedURLException { + String[] tokens = jars.split(File.pathSeparator); + + List urls = new ArrayList(tokens.length); + for (String token : tokens) { + File file = new File(token); + urls.add(file.toURI().toURL()); + } + return urls; + } + + + private static List> loadTestClasses(ClassLoader classLoader, List testClassNames) throws ClassNotFoundException { + List> classes = new ArrayList>(testClassNames.size()); + + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(classLoader); + + for (String testClassName : testClassNames) { + classes.add(classLoader.loadClass(testClassName)); + } + + Thread.currentThread().setContextClassLoader(old); + return classes; + } private static class PrintListener extends RunListener { diff --git a/test/src/main/java/com/nhn/pinpoint/test/fork/OnChildClassLoader.java b/test/src/main/java/com/nhn/pinpoint/test/fork/OnChildClassLoader.java new file mode 100644 index 000000000..09f9bf959 --- /dev/null +++ b/test/src/main/java/com/nhn/pinpoint/test/fork/OnChildClassLoader.java @@ -0,0 +1,11 @@ +package com.nhn.pinpoint.test.fork; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface OnChildClassLoader { +} diff --git a/test/src/main/java/com/nhn/pinpoint/test/fork/PinpointAgentPath.java b/test/src/main/java/com/nhn/pinpoint/test/fork/PinpointAgentPath.java index 7fc6da228..54185919b 100644 --- a/test/src/main/java/com/nhn/pinpoint/test/fork/PinpointAgentPath.java +++ b/test/src/main/java/com/nhn/pinpoint/test/fork/PinpointAgentPath.java @@ -1,4 +1,4 @@ -package com.nhn.pinpoint.profiler.util; +package com.nhn.pinpoint.test.fork; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -7,6 +7,6 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) -public @interface PinpointAgent { - String value(); +public @interface PinpointAgentPath { + String value() default "target/pinpoint-agent"; } diff --git a/test/src/main/java/com/nhn/pinpoint/test/fork/PinpointConfig.java b/test/src/main/java/com/nhn/pinpoint/test/fork/PinpointConfig.java index df5d6d208..86063829c 100644 --- a/test/src/main/java/com/nhn/pinpoint/test/fork/PinpointConfig.java +++ b/test/src/main/java/com/nhn/pinpoint/test/fork/PinpointConfig.java @@ -1,4 +1,4 @@ -package com.nhn.pinpoint.profiler.util; +package com.nhn.pinpoint.test.fork; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/test/src/main/java/com/nhn/pinpoint/test/fork/WithLibraries.java b/test/src/main/java/com/nhn/pinpoint/test/fork/WithLibraries.java new file mode 100644 index 000000000..e3a26504d --- /dev/null +++ b/test/src/main/java/com/nhn/pinpoint/test/fork/WithLibraries.java @@ -0,0 +1,12 @@ +package com.nhn.pinpoint.test.fork; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface WithLibraries { + String[] value() default {}; +}