From 51ffd5a0de739b55a5c8ed533b85fb638b5dfb88 Mon Sep 17 00:00:00 2001 From: Jaehong Kim Date: Thu, 20 Aug 2015 10:57:32 +0900 Subject: [PATCH 1/2] change new plugin. --- .../pinpoint/plugin/redis/CommandContext.java | 92 +++++++ .../plugin/redis/EndPointAccessor.java | 6 + .../pinpoint/plugin/redis/RedisConstants.java | 5 +- .../pinpoint/plugin/redis/RedisPlugin.java | 240 +++++++++++------- .../plugin/redis/RedisPluginConfig.java | 10 +- .../plugin/redis/RedisTypeProvider.java | 4 +- .../JedisClientConstructorInterceptor.java | 14 +- .../JedisClientMetadataAttchInterceptor.java | 21 +- .../JedisConstructorInterceptor.java | 15 +- .../interceptor/JedisMethodInterceptor.java | 52 +++- .../JedisPipelineConstructorInterceptor.java | 6 +- .../JedisPipelineMethodInterceptor.java | 57 ++++- ...disPipelineSetClientMethodInterceptor.java | 6 +- ...olSendCommandAndReadMethodInterceptor.java | 108 ++++++++ 14 files changed, 482 insertions(+), 154 deletions(-) create mode 100644 plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/CommandContext.java create mode 100644 plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/EndPointAccessor.java create mode 100644 plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/CommandContext.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/CommandContext.java new file mode 100644 index 000000000..2010bc0d9 --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/CommandContext.java @@ -0,0 +1,92 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.redis; + +/** + * + * @author jaehong.kim + * + */ +public class CommandContext { + private long readBeginTime; + private long readEndTime; + private boolean readFail; + + private long writeBeginTime; + private long writeEndTime; + private boolean writeFail; + + public void setReadBeginTime(long readBeginTime) { + this.readBeginTime = readBeginTime; + } + + public void setReadEndTime(long readEndTime) { + this.readEndTime = readEndTime; + } + + public boolean isReadFail() { + return readFail; + } + + public void setReadFail(boolean readFail) { + this.readFail = readFail; + } + + public void setWriteBeginTime(long writeBeginTime) { + this.writeBeginTime = writeBeginTime; + } + + public void setWriteEndTime(long writeEndTime) { + this.writeEndTime = writeEndTime; + } + + public boolean isWriteFail() { + return writeFail; + } + + public void setWriteFail(boolean writeFail) { + this.writeFail = writeFail; + } + + public long getWriteElapsedTime() { + long result = writeEndTime - writeBeginTime; + return result > 0 ? result : 0; + } + + public long getReadElapsedTime() { + long result = readEndTime - readBeginTime; + return result > 0 ? result : 0; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("{readBeginTime="); + builder.append(readBeginTime); + builder.append(", readEndTime="); + builder.append(readEndTime); + builder.append(", readFail="); + builder.append(readFail); + builder.append(", writeBeginTime="); + builder.append(writeBeginTime); + builder.append(", writeEndTime="); + builder.append(writeEndTime); + builder.append(", writeFail="); + builder.append(writeFail); + builder.append("}"); + return builder.toString(); + } +} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/EndPointAccessor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/EndPointAccessor.java new file mode 100644 index 000000000..ca6c62328 --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/EndPointAccessor.java @@ -0,0 +1,6 @@ +package com.navercorp.pinpoint.plugin.redis; + +public interface EndPointAccessor { + public void _$PINPOINT$_setEndPoint(String endPoint); + public String _$PINPOINT$_getEndPoint(); +} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisConstants.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisConstants.java index 9802f9bdc..3481a09f3 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisConstants.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisConstants.java @@ -28,6 +28,7 @@ import com.navercorp.pinpoint.common.trace.ServiceType; public interface RedisConstants { public static final ServiceType REDIS = ServiceType.of(8200, "REDIS", FAST_SCHEMA, TERMINAL, RECORD_STATISTICS); - public static final String METADATA_END_POINT = "endPoint"; - public static final String METADATA_DESTINATION_ID = "destinationId"; + public static final String METADATA_END_POINT = "com.navercorp.pinpoint.plugin.redis.EndPointAccessor"; + + public static final String REDIS_SCOPE = "redisScope"; } diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java index efc540788..a9097ba02 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java @@ -15,15 +15,18 @@ */ package com.navercorp.pinpoint.plugin.redis; +import java.security.ProtectionDomain; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginInstrumentContext; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; -import com.navercorp.pinpoint.bootstrap.plugin.transformer.ClassFileTransformerBuilder; -import com.navercorp.pinpoint.bootstrap.plugin.transformer.ConstructorTransformerBuilder; -import com.navercorp.pinpoint.bootstrap.plugin.transformer.MethodTransformerBuilder; -import com.navercorp.pinpoint.bootstrap.plugin.transformer.MethodTransformerExceptionHandler; -import com.navercorp.pinpoint.bootstrap.plugin.transformer.MethodTransformerProperty; +import com.navercorp.pinpoint.bootstrap.plugin.transformer.PinpointClassFileTransformer; import com.navercorp.pinpoint.plugin.redis.filter.JedisMethodNames; import com.navercorp.pinpoint.plugin.redis.filter.JedisPipelineMethodNames; import com.navercorp.pinpoint.plugin.redis.filter.NameBasedMethodFilter; @@ -34,26 +37,6 @@ import com.navercorp.pinpoint.plugin.redis.filter.NameBasedMethodFilter; * */ public class RedisPlugin implements ProfilerPlugin, RedisConstants { - - private static final String STRING = "java.lang.String"; - private static final String INT = "int"; - private static final String URI = "java.net.URI"; - - private static final String JEDIS = "redis.clients.jedis.Jedis"; - private static final String BINARY_JEDIS = "redis.clients.jedis.BinaryJedis"; - private static final String JEDIS_CLIENT = "redis.clients.jedis.Client"; - private static final String JEDIS_PIPELINE_BASE = "redis.clients.jedis.PipelineBase"; - private static final String JEDIS_MULTIKEY_PIPELINE_BASE = "redis.clients.jedis.MultiKeyPipelineBase"; - private static final String JEDIS_PIPELINE = "redis.clients.jedis.Pipeline"; - private static final String JEDIS_SHARD_INFO = "redis.clients.jedis.JedisShardInfo"; - - private static final String JEDIS_CONSTRUCTOR_INTERCEPTOR = "com.navercorp.pinpoint.plugin.redis.interceptor.JedisConstructorInterceptor"; - private static final String JEDIS_METHODS_INTERCEPTOR = "com.navercorp.pinpoint.plugin.redis.interceptor.JedisMethodInterceptor"; - private static final String JEDIS_CLIENT_CONSTRUCTOR_INTERCEPTOR = "com.navercorp.pinpoint.plugin.redis.interceptor.JedisClientConstructorInterceptor"; - private static final String JEDIS_PIPELINE_METHODS_INTERCEPTOR = "com.navercorp.pinpoint.plugin.redis.interceptor.JedisPipelineMethodInterceptor"; - private static final String JEDIS_PIPELINE_SET_CLIENT_METHOD_INTERCEPTOR = "com.navercorp.pinpoint.plugin.redis.interceptor.JedisPipelineSetClientMethodInterceptor"; - private static final String JEDIS_PIPELINE_CONSTRUCTOR_INTERCEPTOR = "com.navercorp.pinpoint.plugin.redis.interceptor.JedisPipelineConstructorInterceptor"; - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); @Override @@ -65,6 +48,7 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants { if (enabled) { // jedis addJedisClassEditors(context, config); + addProtocolClassEditor(context, config); if (pipelineEnabled) { // jedis pipeline @@ -76,102 +60,164 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants { // Jedis & BinaryJedis private void addJedisClassEditors(ProfilerPluginSetupContext context, RedisPluginConfig config) { - final ClassFileTransformerBuilder classEditorBuilder = addJedisExtendedClassEditor(context, config, BINARY_JEDIS); - classEditorBuilder.injectMetadata(METADATA_END_POINT); - context.addClassFileTransformer(classEditorBuilder.build()); + addJedisExtendedClassEditor(context, config, "redis.clients.jedis.BinaryJedis", new TransformHandler() { - // Jedis extends BinaryJedis - context.addClassFileTransformer(addJedisExtendedClassEditor(context, config, JEDIS).build()); - - } - - private ClassFileTransformerBuilder addJedisExtendedClassEditor(ProfilerPluginSetupContext context, RedisPluginConfig config, final String targetClassName) { - final ClassFileTransformerBuilder classEditorBuilder = context.getClassFileTransformerBuilder(targetClassName); - - final ConstructorTransformerBuilder constructorEditorBuilderArg1 = classEditorBuilder.editConstructor(STRING); - constructorEditorBuilderArg1.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); - constructorEditorBuilderArg1.injectInterceptor(JEDIS_CONSTRUCTOR_INTERCEPTOR); - - final ConstructorTransformerBuilder constructorEditorBuilderArg2 = classEditorBuilder.editConstructor(STRING, INT); - constructorEditorBuilderArg2.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); - constructorEditorBuilderArg2.injectInterceptor(JEDIS_CONSTRUCTOR_INTERCEPTOR); - - final ConstructorTransformerBuilder constructorEditorBuilderArg3 = classEditorBuilder.editConstructor(STRING, INT, INT); - constructorEditorBuilderArg3.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); - constructorEditorBuilderArg3.injectInterceptor(JEDIS_CONSTRUCTOR_INTERCEPTOR); - - final ConstructorTransformerBuilder constructorEditorBuilderArg4 = classEditorBuilder.editConstructor(URI); - constructorEditorBuilderArg4.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); - constructorEditorBuilderArg4.injectInterceptor(JEDIS_CONSTRUCTOR_INTERCEPTOR); - - final ConstructorTransformerBuilder constructorEditorBuilderArg5 = classEditorBuilder.editConstructor(JEDIS_SHARD_INFO); - constructorEditorBuilderArg5.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); - constructorEditorBuilderArg5.injectInterceptor(JEDIS_CONSTRUCTOR_INTERCEPTOR); - - final MethodTransformerBuilder methodEditorBuilder = classEditorBuilder.editMethods(new NameBasedMethodFilter(JedisMethodNames.get())); - methodEditorBuilder.exceptionHandler(new MethodTransformerExceptionHandler() { @Override - public void handle(String targetClassName, String targetMethodName, String[] targetMethodParameterTypes, Throwable exception) throws Exception { - if (logger.isWarnEnabled()) { - logger.warn("Unsupported method " + targetClassName + "." + targetMethodName, exception); - } + public void handle(InstrumentClass target) throws InstrumentException { + target.addField(METADATA_END_POINT); } }); - methodEditorBuilder.injectInterceptor(JEDIS_METHODS_INTERCEPTOR); - return classEditorBuilder; + // Jedis extends BinaryJedis + addJedisExtendedClassEditor(context, config, "redis.clients.jedis.Jedis", null); + } + + private void addJedisExtendedClassEditor(ProfilerPluginSetupContext context, final RedisPluginConfig config, final String targetClassName, final TransformHandler handler) { + context.addClassFileTransformer(targetClassName, new PinpointClassFileTransformer() { + + @Override + public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentContext.getInstrumentClass(classLoader, className, classfileBuffer); + if (handler != null) { + handler.handle(target); + } + + final InstrumentMethod constructorEditorBuilderArg1 = target.getConstructor("java.lang.String"); + if (constructorEditorBuilderArg1 != null) { + constructorEditorBuilderArg1.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisConstructorInterceptor"); + } + + final InstrumentMethod constructorEditorBuilderArg2 = target.getConstructor("java.lang.String", "int"); + if (constructorEditorBuilderArg2 != null) { + constructorEditorBuilderArg2.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisConstructorInterceptor"); + } + + final InstrumentMethod constructorEditorBuilderArg3 = target.getConstructor("java.lang.String", "int", "int"); + if (constructorEditorBuilderArg3 != null) { + constructorEditorBuilderArg3.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisConstructorInterceptor"); + } + + final InstrumentMethod constructorEditorBuilderArg4 = target.getConstructor("java.net.URI"); + if (constructorEditorBuilderArg4 != null) { + constructorEditorBuilderArg4.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisConstructorInterceptor"); + } + + final InstrumentMethod constructorEditorBuilderArg5 = target.getConstructor("redis.clients.jedis.JedisShardInfo"); + if (constructorEditorBuilderArg5 != null) { + constructorEditorBuilderArg5.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisConstructorInterceptor"); + } + + for (InstrumentMethod method : target.getDeclaredMethods(new NameBasedMethodFilter(JedisMethodNames.get()))) { + try { + method.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisMethodInterceptor", config.isIo()); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + + return target.toBytecode(); + } + }); } // Client private void addJedisClientClassEditor(ProfilerPluginSetupContext context, RedisPluginConfig config) { - final ClassFileTransformerBuilder classEditorBuilder = context.getClassFileTransformerBuilder(JEDIS_CLIENT); - classEditorBuilder.injectMetadata(METADATA_END_POINT); + context.addClassFileTransformer("redis.clients.jedis.Client", new PinpointClassFileTransformer() { - final ConstructorTransformerBuilder constructorEditorBuilderArg1 = classEditorBuilder.editConstructor(STRING); - constructorEditorBuilderArg1.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); - constructorEditorBuilderArg1.injectInterceptor(JEDIS_CLIENT_CONSTRUCTOR_INTERCEPTOR); - - final ConstructorTransformerBuilder constructorEditorBuilderArg2 = classEditorBuilder.editConstructor(STRING, INT); - constructorEditorBuilderArg2.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); - constructorEditorBuilderArg2.injectInterceptor(JEDIS_CLIENT_CONSTRUCTOR_INTERCEPTOR); + @Override + public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentContext.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(METADATA_END_POINT); - context.addClassFileTransformer(classEditorBuilder.build()); + final InstrumentMethod constructorEditorBuilderArg1 = target.getConstructor("java.lang.String"); + if (constructorEditorBuilderArg1 != null) { + constructorEditorBuilderArg1.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisClientConstructorInterceptor"); + } + + final InstrumentMethod constructorEditorBuilderArg2 = target.getConstructor("java.lang.String", "int"); + if (constructorEditorBuilderArg2 != null) { + constructorEditorBuilderArg2.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisClientConstructorInterceptor"); + } + + return target.toBytecode(); + } + }); } + + + private void addProtocolClassEditor(ProfilerPluginSetupContext context, RedisPluginConfig config) { + context.addClassFileTransformer("redis.clients.jedis.Protocol", new PinpointClassFileTransformer() { + + @Override + public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentContext.getInstrumentClass(classLoader, className, classfileBuffer); + + for(InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("sendCommand", "read"))) { + method.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.ProtocolSendCommandAndReadMethodInterceptor"); + } + + return target.toBytecode(); + } + }); + } + + // Pipeline private void addJedisPipelineClassEditors(ProfilerPluginSetupContext context, RedisPluginConfig config) { - context.addClassFileTransformer(addJedisPipelineBaseExtendedClassEditor(context, config, JEDIS_PIPELINE_BASE).build()); + addJedisPipelineBaseExtendedClassEditor(context, config, "redis.clients.jedis.PipelineBase", null); // MultikeyPipellineBase extends PipelineBase - context.addClassFileTransformer(addJedisPipelineBaseExtendedClassEditor(context, config, JEDIS_MULTIKEY_PIPELINE_BASE).build()); + addJedisPipelineBaseExtendedClassEditor(context, config, "redis.clients.jedis.MultiKeyPipelineBase", null); // Pipeline extends PipelineBase - final ClassFileTransformerBuilder classEditorBuilder = addJedisPipelineBaseExtendedClassEditor(context, config, JEDIS_PIPELINE); - classEditorBuilder.injectMetadata(METADATA_END_POINT); - final MethodTransformerBuilder setClientMethodEditorBuilder = classEditorBuilder.editMethod("setClient", JEDIS_CLIENT); - setClientMethodEditorBuilder.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); - setClientMethodEditorBuilder.injectInterceptor(JEDIS_PIPELINE_SET_CLIENT_METHOD_INTERCEPTOR); + addJedisPipelineBaseExtendedClassEditor(context, config, "redis.clients.jedis.Pipeline", new TransformHandler() { - final ConstructorTransformerBuilder constructorEditorBuilder = classEditorBuilder.editConstructor(JEDIS_CLIENT); - constructorEditorBuilder.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); - constructorEditorBuilder.injectInterceptor(JEDIS_PIPELINE_CONSTRUCTOR_INTERCEPTOR); - context.addClassFileTransformer(classEditorBuilder.build()); - } - - private ClassFileTransformerBuilder addJedisPipelineBaseExtendedClassEditor(ProfilerPluginSetupContext context, RedisPluginConfig config, String targetClassName) { - final ClassFileTransformerBuilder classEditorBuilder = context.getClassFileTransformerBuilder(targetClassName); - - final MethodTransformerBuilder methodEditorBuilder = classEditorBuilder.editMethods(new NameBasedMethodFilter(JedisPipelineMethodNames.get())); - methodEditorBuilder.exceptionHandler(new MethodTransformerExceptionHandler() { @Override - public void handle(String targetClassName, String targetMethodName, String[] targetMethodParameterTypes, Throwable exception) throws Exception { - if (logger.isWarnEnabled()) { - logger.warn("Unsupported method " + targetClassName + "." + targetMethodName, exception); + public void handle(InstrumentClass target) throws InstrumentException { + target.addField(METADATA_END_POINT); + + final InstrumentMethod setClientMethodEditorBuilder = target.getDeclaredMethod("setClient", "redis.clients.jedis.Client"); + if (setClientMethodEditorBuilder != null) { + setClientMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisPipelineSetClientMethodInterceptor"); + } + + final InstrumentMethod constructorEditorBuilder = target.getConstructor("redis.clients.jedis.Client"); + if (constructorEditorBuilder != null) { + constructorEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisPipelineConstructorInterceptor"); } } }); - methodEditorBuilder.injectInterceptor(JEDIS_PIPELINE_METHODS_INTERCEPTOR); + } - return classEditorBuilder; + private void addJedisPipelineBaseExtendedClassEditor(ProfilerPluginSetupContext context, final RedisPluginConfig config, String targetClassName, final TransformHandler handler) { + context.addClassFileTransformer(targetClassName, new PinpointClassFileTransformer() { + + @Override + public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentContext.getInstrumentClass(classLoader, className, classfileBuffer); + if (handler != null) { + handler.handle(target); + } + + for (InstrumentMethod method : target.getDeclaredMethods(new NameBasedMethodFilter(JedisPipelineMethodNames.get()))) { + try { + method.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisPipelineMethodInterceptor", config.isIo()); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + + return target.toBytecode(); + } + }); + } + + private interface TransformHandler { + void handle(InstrumentClass target) throws InstrumentException; } } \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPluginConfig.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPluginConfig.java index 417b87774..254315bb9 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPluginConfig.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPluginConfig.java @@ -26,10 +26,12 @@ public class RedisPluginConfig { private boolean enabled = true; private boolean pipelineEnabled = true; + private boolean io = true; public RedisPluginConfig(ProfilerConfig src) { enabled = src.readBoolean("profiler.redis", true); pipelineEnabled = src.readBoolean("profiler.redis.pipeline", true); + io = src.readBoolean("profiler.redis.io", true); } public boolean isEnabled() { @@ -40,6 +42,10 @@ public class RedisPluginConfig { return pipelineEnabled; } + public boolean isIo() { + return io; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -47,7 +53,9 @@ public class RedisPluginConfig { builder.append(enabled); builder.append(", pipelineEnabled="); builder.append(pipelineEnabled); + builder.append(", io="); + builder.append(io); builder.append("}"); return builder.toString(); } -} +} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisTypeProvider.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisTypeProvider.java index 7514ef678..420fe7c7f 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisTypeProvider.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisTypeProvider.java @@ -18,10 +18,12 @@ package com.navercorp.pinpoint.plugin.redis; import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; +import static com.navercorp.pinpoint.common.trace.AnnotationKeyMatcher.*; + public class RedisTypeProvider implements TraceMetadataProvider, RedisConstants{ @Override public void setup(TraceMetadataSetupContext context) { - context.addServiceType(REDIS); + context.addServiceType(REDIS, ARGS_MATCHER); } } diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisClientConstructorInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisClientConstructorInterceptor.java index f422fdf63..29a3469d2 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisClientConstructorInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisClientConstructorInterceptor.java @@ -16,13 +16,12 @@ package com.navercorp.pinpoint.plugin.redis.interceptor; -import com.navercorp.pinpoint.bootstrap.MetadataAccessor; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; +import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; import com.navercorp.pinpoint.plugin.redis.RedisConstants; /** @@ -36,10 +35,7 @@ public class JedisClientConstructorInterceptor implements SimpleAroundIntercepto private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private MetadataAccessor endPointAccessor; - - public JedisClientConstructorInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, @Name(METADATA_END_POINT) MetadataAccessor endPointAccessor) { - this.endPointAccessor = endPointAccessor; + public JedisClientConstructorInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { } @Override @@ -64,7 +60,7 @@ public class JedisClientConstructorInterceptor implements SimpleAroundIntercepto // set default port endPoint.append(":").append(6379); } - endPointAccessor.set(target, endPoint.toString()); + ((EndPointAccessor)target)._$PINPOINT$_setEndPoint(endPoint.toString()); } catch (Throwable t) { logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); } @@ -81,8 +77,8 @@ public class JedisClientConstructorInterceptor implements SimpleAroundIntercepto return false; } - if (!endPointAccessor.isApplicable(target)) { - logger.debug("Invalid target object. Need metadata accessor({}).", METADATA_DESTINATION_ID); + if (!(target instanceof EndPointAccessor)) { + logger.debug("Invalid target object. Need field accessor({}).", METADATA_END_POINT); return false; } diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisClientMetadataAttchInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisClientMetadataAttchInterceptor.java index 8461db053..fbeba8aa9 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisClientMetadataAttchInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisClientMetadataAttchInterceptor.java @@ -17,13 +17,12 @@ package com.navercorp.pinpoint.plugin.redis.interceptor; import redis.clients.jedis.Client; -import com.navercorp.pinpoint.bootstrap.MetadataAccessor; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; +import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; import com.navercorp.pinpoint.plugin.redis.RedisConstants; /** @@ -35,10 +34,7 @@ public abstract class JedisClientMetadataAttchInterceptor implements SimpleAroun private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private MetadataAccessor endPointAccessor; - - public JedisClientMetadataAttchInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, @Name(METADATA_END_POINT) MetadataAccessor endPointAccessor) { - this.endPointAccessor = endPointAccessor; + public JedisClientMetadataAttchInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { } @Override @@ -52,9 +48,9 @@ public abstract class JedisClientMetadataAttchInterceptor implements SimpleAroun return; } - final String endPoint = endPointAccessor.get(args[0]); + final String endPoint = ((EndPointAccessor) args[0])._$PINPOINT$_getEndPoint(); if (endPoint != null) { - endPointAccessor.set(target, endPoint); + ((EndPointAccessor) target)._$PINPOINT$_setEndPoint(endPoint); } } catch (Throwable t) { logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); @@ -72,8 +68,13 @@ public abstract class JedisClientMetadataAttchInterceptor implements SimpleAroun return false; } - if (!endPointAccessor.isApplicable(target)) { - logger.debug("Invalid target object. Need metadata accessor({}).", METADATA_END_POINT); + if (!(args[0] instanceof EndPointAccessor)) { + logger.debug("Invalid args[0] object. Need field accessor({}).", METADATA_END_POINT); + return false; + } + + if (!(target instanceof EndPointAccessor)) { + logger.debug("Invalid target object. Need field accessor({}).", METADATA_END_POINT); return false; } diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisConstructorInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisConstructorInterceptor.java index abf3599b7..599f1333e 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisConstructorInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisConstructorInterceptor.java @@ -20,13 +20,12 @@ import java.net.URI; import redis.clients.jedis.JedisShardInfo; -import com.navercorp.pinpoint.bootstrap.MetadataAccessor; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; +import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; import com.navercorp.pinpoint.plugin.redis.RedisConstants; /** @@ -41,10 +40,7 @@ public class JedisConstructorInterceptor implements SimpleAroundInterceptor, Red private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private MetadataAccessor endPointAccessor; - - public JedisConstructorInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, @Name(METADATA_END_POINT) MetadataAccessor endPointAccessor) { - this.endPointAccessor = endPointAccessor; + public JedisConstructorInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { } @Override @@ -80,8 +76,7 @@ public class JedisConstructorInterceptor implements SimpleAroundInterceptor, Red endPoint.append(":"); endPoint.append(info.getPort()); } - - endPointAccessor.set(target, endPoint.toString()); + ((EndPointAccessor)target)._$PINPOINT$_setEndPoint(endPoint.toString()); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); @@ -95,8 +90,8 @@ public class JedisConstructorInterceptor implements SimpleAroundInterceptor, Red return false; } - if (!endPointAccessor.isApplicable(target)) { - logger.debug("Invalid target object. Need metadata accessor({}).", METADATA_END_POINT); + if (!(target instanceof EndPointAccessor)) { + logger.debug("Invalid target object. Need field accessor({}).", METADATA_END_POINT); return false; } diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisMethodInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisMethodInterceptor.java index 13a48a346..344d0ada3 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisMethodInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisMethodInterceptor.java @@ -16,12 +16,17 @@ package com.navercorp.pinpoint.plugin.redis.interceptor; -import com.navercorp.pinpoint.bootstrap.MetadataAccessor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.instrument.AttachmentFactory; import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; -import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; +import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroup; +import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroupInvocation; +import com.navercorp.pinpoint.bootstrap.plugin.annotation.Group; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.redis.CommandContext; +import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; import com.navercorp.pinpoint.plugin.redis.RedisConstants; /** @@ -30,26 +35,59 @@ import com.navercorp.pinpoint.plugin.redis.RedisConstants; * @author jaehong.kim * */ +@Group(value = RedisConstants.REDIS_SCOPE) public class JedisMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin implements RedisConstants { - private MetadataAccessor endPointAccessor; + private InterceptorGroup interceptorGroup; + private boolean io; - public JedisMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, @Name(METADATA_END_POINT) MetadataAccessor endPointAccessor) { + public JedisMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorGroup interceptorGroup, boolean io) { super(traceContext, methodDescriptor); - this.endPointAccessor = endPointAccessor; + this.interceptorGroup = interceptorGroup; + this.io = io; } @Override public void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + final InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); + if (invocation != null) { + final CommandContext callContext = (CommandContext) invocation.getOrCreateAttachment(new AttachmentFactory() { + @Override + public Object createAttachment() { + return new CommandContext(); + } + }); + invocation.setAttachment(callContext); + } } @Override public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { String endPoint = null; - if (endPointAccessor.isApplicable(target)) { - endPoint = endPointAccessor.get(target); + if (target instanceof EndPointAccessor) { + endPoint = ((EndPointAccessor) target)._$PINPOINT$_getEndPoint(); + } + + final InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); + if (invocation != null && invocation.getAttachment() != null) { + final CommandContext commandContext = (CommandContext) invocation.getAttachment(); + logger.debug("Check command context {}", commandContext); + if (io) { + final StringBuilder sb = new StringBuilder(); + sb.append("write=").append(commandContext.getWriteElapsedTime()); + if (commandContext.isWriteFail()) { + sb.append("(fail)"); + } + sb.append(", read=").append(commandContext.getReadElapsedTime()); + if (commandContext.isReadFail()) { + sb.append("(fail)"); + } + recorder.recordAttribute(AnnotationKey.ARGS0, sb.toString()); + } + // clear + invocation.removeAttachment(); } recorder.recordApi(getMethodDescriptor()); diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineConstructorInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineConstructorInterceptor.java index d7ccd9897..130146578 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineConstructorInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineConstructorInterceptor.java @@ -16,10 +16,8 @@ package com.navercorp.pinpoint.plugin.redis.interceptor; -import com.navercorp.pinpoint.bootstrap.MetadataAccessor; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; /** * Jedis Pipeline(redis client) constructor interceptor @@ -30,7 +28,7 @@ import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; */ public class JedisPipelineConstructorInterceptor extends JedisClientMetadataAttchInterceptor { - public JedisPipelineConstructorInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, @Name(METADATA_END_POINT) MetadataAccessor endPointAccessor) { - super(traceContext, methodDescriptor, endPointAccessor); + public JedisPipelineConstructorInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); } } \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineMethodInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineMethodInterceptor.java index 840102dde..b9a9ba380 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineMethodInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineMethodInterceptor.java @@ -16,12 +16,17 @@ package com.navercorp.pinpoint.plugin.redis.interceptor; -import com.navercorp.pinpoint.bootstrap.MetadataAccessor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.instrument.AttachmentFactory; import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; -import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; +import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroup; +import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroupInvocation; +import com.navercorp.pinpoint.bootstrap.plugin.annotation.Group; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.redis.CommandContext; +import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; import com.navercorp.pinpoint.plugin.redis.RedisConstants; /** @@ -30,26 +35,60 @@ import com.navercorp.pinpoint.plugin.redis.RedisConstants; * @author jaehong.kim * */ +@Group(value = RedisConstants.REDIS_SCOPE) public class JedisPipelineMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin implements RedisConstants { - private MetadataAccessor endPointAccessor; - - public JedisPipelineMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, @Name(METADATA_END_POINT) MetadataAccessor endPointAccessor) { + + private InterceptorGroup interceptorGroup; + private boolean io; + + public JedisPipelineMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorGroup interceptorGroup, boolean io) { super(traceContext, methodDescriptor); - - this.endPointAccessor = endPointAccessor; + + this.interceptorGroup = interceptorGroup; + this.io = io; } @Override public void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + final InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); + if (invocation != null) { + final CommandContext callContext = (CommandContext) invocation.getOrCreateAttachment(new AttachmentFactory() { + @Override + public Object createAttachment() { + return new CommandContext(); + } + }); + invocation.setAttachment(callContext); + } } @Override public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { String endPoint = null; - if (endPointAccessor.isApplicable(target)) { - endPoint = endPointAccessor.get(target); + if (target instanceof EndPointAccessor) { + endPoint = ((EndPointAccessor)target)._$PINPOINT$_getEndPoint(); } + final InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); + if (invocation != null && invocation.getAttachment() != null) { + final CommandContext commandContext = (CommandContext) invocation.getAttachment(); + logger.debug("Check command context {}", commandContext); + if (io) { + final StringBuilder sb = new StringBuilder(); + sb.append("write=").append(commandContext.getWriteElapsedTime()); + if (commandContext.isWriteFail()) { + sb.append("(fail)"); + } + sb.append(", read=").append(commandContext.getReadElapsedTime()); + if (commandContext.isReadFail()) { + sb.append("(fail)"); + } + recorder.recordAttribute(AnnotationKey.ARGS0, sb.toString()); + } + // clear + invocation.removeAttachment(); + } + recorder.recordApi(getMethodDescriptor()); recorder.recordEndPoint(endPoint != null ? endPoint : "Unknown"); recorder.recordDestinationId(REDIS.getName()); diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineSetClientMethodInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineSetClientMethodInterceptor.java index f5cf038b3..4ad7080d3 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineSetClientMethodInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisPipelineSetClientMethodInterceptor.java @@ -16,10 +16,8 @@ package com.navercorp.pinpoint.plugin.redis.interceptor; -import com.navercorp.pinpoint.bootstrap.MetadataAccessor; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; /** * Jedis pipeline (redis client) setClient method interceptor @@ -29,7 +27,7 @@ import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; */ public class JedisPipelineSetClientMethodInterceptor extends JedisClientMetadataAttchInterceptor { - public JedisPipelineSetClientMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, @Name(METADATA_END_POINT) MetadataAccessor endPointAccessor) { - super(traceContext, methodDescriptor, endPointAccessor); + public JedisPipelineSetClientMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); } } \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java new file mode 100644 index 000000000..a8696d3cf --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java @@ -0,0 +1,108 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.redis.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.group.ExecutionPolicy; +import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroup; +import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroupInvocation; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.annotation.Group; +import com.navercorp.pinpoint.plugin.redis.CommandContext; +import com.navercorp.pinpoint.plugin.redis.RedisConstants; + +/** + * RedisConnection(nBase-ARC client) constructor interceptor - trace endPoint + * + * @author jaehong.kim + * + */ +@Group(value = RedisConstants.REDIS_SCOPE, executionPolicy = ExecutionPolicy.INTERNAL) +public class ProtocolSendCommandAndReadMethodInterceptor implements SimpleAroundInterceptor, RedisConstants { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor methodDescriptor; + private InterceptorGroup interceptorGroup; + + public ProtocolSendCommandAndReadMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorGroup interceptorGroup) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; + this.interceptorGroup = interceptorGroup; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + final InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); + if (invocation != null && invocation.getAttachment() != null) { + final CommandContext commandContext = (CommandContext) invocation.getAttachment(); + if (methodDescriptor.getMethodName().equals("sendCommand")) { + commandContext.setWriteBeginTime(System.currentTimeMillis()); + } else { + commandContext.setReadBeginTime(System.currentTimeMillis()); + } + logger.debug("Set command context {}", commandContext); + } + } catch (Throwable t) { + logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, methodDescriptor.getClassName(), methodDescriptor.getMethodName(), "", args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + final InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); + if (invocation != null && invocation.getAttachment() != null) { + final CommandContext commandContext = (CommandContext) invocation.getAttachment(); + if (methodDescriptor.getMethodName().equals("sendCommand")) { + commandContext.setWriteEndTime(System.currentTimeMillis()); + commandContext.setWriteFail(throwable != null); + } else { + commandContext.setReadEndTime(System.currentTimeMillis()); + commandContext.setReadFail(throwable != null); + } + logger.debug("Set command context {}", commandContext); + } + } catch (Throwable t) { + logger.warn("Failed to AFTER process. {}", t.getMessage(), t); + } + } +} \ No newline at end of file From 4db2a58006b9366f25aad1125fae31ffc8ad8328 Mon Sep 17 00:00:00 2001 From: Jaehong Kim Date: Thu, 20 Aug 2015 16:30:53 +0900 Subject: [PATCH 2/2] change MethodFilter --- agent/src/main/resources/pinpoint.config | 9 ++- .../bootstrap/instrument/MethodFilter.java | 4 +- .../bootstrap/instrument/MethodFilters.java | 68 +++++++++++++------ .../redis/{filter => }/JedisMethodNames.java | 20 +----- .../JedisPipelineMethodNames.java | 23 +++---- .../pinpoint/plugin/redis/RedisPlugin.java | 15 ++-- .../redis/filter/NameBasedMethodFilter.java | 57 ---------------- 7 files changed, 74 insertions(+), 122 deletions(-) rename plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/{filter => }/JedisMethodNames.java (92%) rename plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/{filter => }/JedisPipelineMethodNames.java (69%) delete mode 100644 plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/NameBasedMethodFilter.java diff --git a/agent/src/main/resources/pinpoint.config b/agent/src/main/resources/pinpoint.config index 8e3591517..e7a561a2b 100644 --- a/agent/src/main/resources/pinpoint.config +++ b/agent/src/main/resources/pinpoint.config @@ -321,4 +321,11 @@ profiler.google.httpclient.enable=true # Profile async. profiler.google.httpclient.async=true # Maximum anonymous innerclass number. -profiler.google.httpclient.async.innerclassname.max=3 \ No newline at end of file +profiler.google.httpclient.async.innerclassname.max=3 + +########################################################### +# redis +########################################################### +profiler.redis.pipeline +profiler.redis=true +profiler.redis.io=true diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilter.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilter.java index 263311a0a..aaeb27953 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilter.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilter.java @@ -23,6 +23,6 @@ package com.navercorp.pinpoint.bootstrap.instrument; public interface MethodFilter { public static final boolean ACCEPT = true; public static final boolean REJECT = false; - - boolean accept(InstrumentMethod method); + + boolean accept(InstrumentMethod method); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilters.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilters.java index fd2bc3fb3..4ed4fbc04 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilters.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilters.java @@ -21,66 +21,72 @@ import java.util.Arrays; * */ public class MethodFilters { - - private MethodFilters() { } + public static final int SYNTHETIC = 0x00001000; + private MethodFilters() { + } + public static final MethodFilter ACCEPT_ALL = new MethodFilter() { @Override public boolean accept(InstrumentMethod method) { return ACCEPT; } - }; - + public static MethodFilter name(String... names) { - return new MethodNameFilter(names); + return new MethodNameFilter(null, names); + } + + public static MethodFilter name(int[] rejectModifiers, String... names) { + return new MethodNameFilter(rejectModifiers, names); } public static MethodFilter modifier(int required) { return modifier(required, 0); } - + public static MethodFilter modifierNot(int rejected) { return modifier(0, rejected); } - + public static MethodFilter modifier(int required, int rejected) { return new ModifierFilter(required, rejected); } - + public static MethodFilter argAt(int index, String type) { return new ArgAtFilter(index, type); } - + public static MethodFilter args(String... types) { return new ArgsFilter(types); } - - + private static final class MethodNameFilter implements MethodFilter { private final String[] names; + private final RejectModifiers modifiers; - public MethodNameFilter(String[] names) { + public MethodNameFilter(int[] rejectModifiers, String[] names) { this.names = names; + this.modifiers = new RejectModifiers(rejectModifiers); } @Override public boolean accept(InstrumentMethod method) { for (String name : names) { if (name.equals(method.getName())) { - return ACCEPT; + return modifiers.accept(method.getModifiers()); } } return REJECT; } } - + private static final class ModifierFilter implements MethodFilter { private final int required; private final int rejected; - + public ModifierFilter(int required, int rejected) { this.required = required; this.rejected = rejected; @@ -92,11 +98,11 @@ public class MethodFilters { return ((required & modifier) == required) && ((rejected & modifier) == 0); } } - + private static final class ArgAtFilter implements MethodFilter { private final int index; private final String type; - + public ArgAtFilter(int index, String type) { this.index = index; this.type = type; @@ -105,15 +111,15 @@ public class MethodFilters { @Override public boolean accept(InstrumentMethod method) { String[] paramTypes = method.getParameterTypes(); - + if (paramTypes.length < index + 1) { return REJECT; } - + return type.equals(paramTypes[index]); } } - + private static final class ArgsFilter implements MethodFilter { private final String[] types; @@ -127,4 +133,24 @@ public class MethodFilters { return Arrays.equals(paramTypes, types); } } -} + + private static class RejectModifiers { + private final int[] rejectModifiers; + + public RejectModifiers(int[] rejectModifiers) { + this.rejectModifiers = rejectModifiers; + } + + public boolean accept(int modifier) { + if (rejectModifiers != null) { + for (int rejectModifier : rejectModifiers) { + if (((rejectModifier & modifier) != 0)) { + return false; + } + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/JedisMethodNames.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/JedisMethodNames.java similarity index 92% rename from plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/JedisMethodNames.java rename to plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/JedisMethodNames.java index c805972b4..bd6b1b955 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/JedisMethodNames.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/JedisMethodNames.java @@ -14,11 +14,7 @@ * limitations under the License. */ -package com.navercorp.pinpoint.plugin.redis.filter; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; +package com.navercorp.pinpoint.plugin.redis; /** * Jedis method names @@ -27,16 +23,9 @@ import java.util.Set; * */ public class JedisMethodNames { - - private static Set names = null; - - public static Set get() { - if(names != null) { - return names; - } - - final String[] methodNames = { + public static String[] get() { + return new String[] { "get", "type", "append", @@ -197,8 +186,5 @@ public class JedisMethodNames { "slowlogGetBinary", "info" }; - - names = new HashSet(Arrays.asList(methodNames)); - return names; } } \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/JedisPipelineMethodNames.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/JedisPipelineMethodNames.java similarity index 69% rename from plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/JedisPipelineMethodNames.java rename to plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/JedisPipelineMethodNames.java index 9fc68cd6e..cd3f8521d 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/JedisPipelineMethodNames.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/JedisPipelineMethodNames.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package com.navercorp.pinpoint.plugin.redis.filter; +package com.navercorp.pinpoint.plugin.redis; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Set; +import java.util.List; /** * JedisPipeline method names @@ -27,23 +28,17 @@ import java.util.Set; * */ public class JedisPipelineMethodNames { - - private static Set names = null; - public static Set get() { - if(names != null) { - return names; - } - + public static String[] get() { final String[] methodNames = { "sync", "syncAndReturnAll" }; - final Set jedisMethodNames = JedisMethodNames.get(); - jedisMethodNames.addAll(Arrays.asList(methodNames)); - names = jedisMethodNames; - - return names; + final List names = new ArrayList(); + names.addAll(Arrays.asList(JedisMethodNames.get())); + names.addAll(Arrays.asList(methodNames)); + + return names.toArray(new String[names.size()]); } } \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java index a9097ba02..4f22de500 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java @@ -15,6 +15,7 @@ */ package com.navercorp.pinpoint.plugin.redis; +import java.lang.reflect.Modifier; import java.security.ProtectionDomain; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; @@ -27,9 +28,6 @@ import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginInstrumentContext; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; import com.navercorp.pinpoint.bootstrap.plugin.transformer.PinpointClassFileTransformer; -import com.navercorp.pinpoint.plugin.redis.filter.JedisMethodNames; -import com.navercorp.pinpoint.plugin.redis.filter.JedisPipelineMethodNames; -import com.navercorp.pinpoint.plugin.redis.filter.NameBasedMethodFilter; /** * @@ -107,7 +105,7 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants { constructorEditorBuilderArg5.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisConstructorInterceptor"); } - for (InstrumentMethod method : target.getDeclaredMethods(new NameBasedMethodFilter(JedisMethodNames.get()))) { + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(new int[] { MethodFilters.SYNTHETIC }, JedisMethodNames.get()))) { try { method.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisMethodInterceptor", config.isIo()); } catch (Exception e) { @@ -145,8 +143,7 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants { } }); } - - + private void addProtocolClassEditor(ProfilerPluginSetupContext context, RedisPluginConfig config) { context.addClassFileTransformer("redis.clients.jedis.Protocol", new PinpointClassFileTransformer() { @@ -154,7 +151,7 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants { public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentContext.getInstrumentClass(classLoader, className, classfileBuffer); - for(InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("sendCommand", "read"))) { + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(new int[] { Modifier.PRIVATE }, "sendCommand", "read"))) { method.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.ProtocolSendCommandAndReadMethodInterceptor"); } @@ -163,8 +160,6 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants { }); } - - // Pipeline private void addJedisPipelineClassEditors(ProfilerPluginSetupContext context, RedisPluginConfig config) { addJedisPipelineBaseExtendedClassEditor(context, config, "redis.clients.jedis.PipelineBase", null); @@ -202,7 +197,7 @@ public class RedisPlugin implements ProfilerPlugin, RedisConstants { handler.handle(target); } - for (InstrumentMethod method : target.getDeclaredMethods(new NameBasedMethodFilter(JedisPipelineMethodNames.get()))) { + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(new int[] { MethodFilters.SYNTHETIC }, JedisPipelineMethodNames.get()))) { try { method.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisPipelineMethodInterceptor", config.isIo()); } catch (Exception e) { diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/NameBasedMethodFilter.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/NameBasedMethodFilter.java deleted file mode 100644 index 87292ae63..000000000 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/filter/NameBasedMethodFilter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.redis.filter; - -import java.lang.reflect.Modifier; -import java.util.Set; - -import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter; -import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; - -/** - * Name based on method filter - * - * @author jaehong.kim - * - */ -public class NameBasedMethodFilter implements MethodFilter { - private static final int SYNTHETIC = 0x00001000; - private final Set methodNames; - - public NameBasedMethodFilter(final Set methodNames) { - this.methodNames = methodNames; - } - - @Override - public boolean accept(InstrumentMethod ctMethod) { - final int modifiers = ctMethod.getModifiers(); - - if (isSynthetic(modifiers) || !Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers) || Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - return REJECT; - } - - if (methodNames.contains(ctMethod.getName())) { - return ACCEPT; - } - - return REJECT; - } - - private boolean isSynthetic(int mod) { - return (mod & SYNTHETIC) != 0; - } -} \ No newline at end of file