diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4Plugin.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4Plugin.java index 7158f7eb1..4dfc7189c 100644 --- a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4Plugin.java +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4Plugin.java @@ -85,31 +85,42 @@ public class HttpClient4Plugin implements ProfilerPlugin, HttpClient4Constants { private void addClosableHttpAsyncClientClassEditor(ProfilerPluginSetupContext context, HttpClient4PluginConfig config) { final ClassEditorBuilder classEditorBuilder = context.getClassEditorBuilder("org.apache.http.impl.nio.client.CloseableHttpAsyncClient"); - addAsyncClientInterceptor(classEditorBuilder); - addAsyncInternalClientInterceptor(classEditorBuilder); + injectAsyncClientExecuteInterceptor(classEditorBuilder, "org.apache.http.HttpHost", "org.apache.http.HttpRequest", "org.apache.http.protocol.HttpContext", "org.apache.http.concurrent.FutureCallback"); + injectAsyncClientExecuteInterceptor(classEditorBuilder, "org.apache.http.HttpHost", "org.apache.http.HttpRequest", "org.apache.http.concurrent.FutureCallback"); + injectAsyncInternalClientExecuteInterceptor(classEditorBuilder, "org.apache.http.nio.protocol.HttpAsyncRequestProducer", "org.apache.http.nio.protocol.HttpAsyncResponseConsumer", "org.apache.http.concurrent.FutureCallback"); + injectExecuteMethodByHttpUriRequestInterceptor(classEditorBuilder, "org.apache.http.client.methods.HttpUriRequest", "org.apache.http.concurrent.FutureCallback"); context.addClassEditor(classEditorBuilder.build()); } - private void addAsyncClientInterceptor(final ClassEditorBuilder classEditorBuilder) { - MethodEditorBuilder methodEditorBuilder = classEditorBuilder.editMethod("execute", "org.apache.http.HttpHost", "org.apache.http.HttpRequest", "org.apache.http.protocol.HttpContext", "org.apache.http.concurrent.FutureCallback"); + private void injectAsyncClientExecuteInterceptor(final ClassEditorBuilder classEditorBuilder, String... parameterTypeNames) { + MethodEditorBuilder methodEditorBuilder = classEditorBuilder.editMethod("execute", parameterTypeNames); + methodEditorBuilder.property(MethodEditorProperty.IGNORE_IF_NOT_EXIST); methodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.AsyncClientExecuteInterceptor"); } - private void addAsyncInternalClientInterceptor(final ClassEditorBuilder classEditorBuilder) { - MethodEditorBuilder methodEditorBuilder = classEditorBuilder - .editMethod("execute", "org.apache.http.nio.protocol.HttpAsyncRequestProducer", "org.apache.http.nio.protocol.HttpAsyncResponseConsumer", "org.apache.http.concurrent.FutureCallback"); + private void injectAsyncInternalClientExecuteInterceptor(final ClassEditorBuilder classEditorBuilder, String... parameterTypeNames) { + MethodEditorBuilder methodEditorBuilder = classEditorBuilder.editMethod("execute", parameterTypeNames); + methodEditorBuilder.property(MethodEditorProperty.IGNORE_IF_NOT_EXIST); methodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.AsyncInternalClientExecuteInterceptor"); } + + private void injectExecuteMethodByHttpUriRequestInterceptor(final ClassEditorBuilder classEditorBuilder, String... parameterTypeNames) { + MethodEditorBuilder methodEditorBuilder = classEditorBuilder.editMethod("execute", parameterTypeNames); + methodEditorBuilder.property(MethodEditorProperty.IGNORE_IF_NOT_EXIST); + methodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.AsyncInternalClientExecuteInterceptor"); + } + private void addDefaultClientExchangeHandlerImplConstructorInterceptor(ProfilerPluginSetupContext context, HttpClient4PluginConfig config) { final ClassEditorBuilder classEditorBuilder = context.getClassEditorBuilder("org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl"); - ConstructorEditorBuilder constructorEditorBuilder = classEditorBuilder.editConstructor("org.apache.commons.logging.Log", "org.apache.http.nio.protocol.HttpAsyncRequestProducer", "org.apache.http.nio.protocol.HttpAsyncResponseConsumer", "org.apache.http.client.protocol.HttpClientContext", "org.apache.http.concurrent.BasicFuture", "org.apache.http.nio.conn.NHttpClientConnectionManager", "org.apache.http.impl.nio.client.InternalClientExec"); + ConstructorEditorBuilder constructorEditorBuilder = classEditorBuilder.editConstructor("org.apache.commons.logging.Log", "org.apache.http.nio.protocol.HttpAsyncRequestProducer", "org.apache.http.nio.protocol.HttpAsyncResponseConsumer", + "org.apache.http.client.protocol.HttpClientContext", "org.apache.http.concurrent.BasicFuture", "org.apache.http.nio.conn.NHttpClientConnectionManager", "org.apache.http.impl.nio.client.InternalClientExec"); constructorEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.DefaultClientExchangeHandlerImplConstructorInterceptor"); - + context.addClassEditor(classEditorBuilder.build()); } - + private void addClosableHttpClientClassEditor(ProfilerPluginSetupContext context, HttpClient4PluginConfig config) { final ClassEditorBuilder classEditorBuilder = context.getClassEditorBuilder("org.apache.http.impl.client.CloseableHttpClient"); injectHttpRequestExecuteMethodInterceptor(classEditorBuilder, "org.apache.http.HttpHost", "org.apache.http.HttpRequest"); @@ -128,22 +139,22 @@ public class HttpClient4Plugin implements ProfilerPlugin, HttpClient4Constants { private void addBasicFutureClassEditor(ProfilerPluginSetupContext context, HttpClient4PluginConfig config) { final ClassEditorBuilder classEditorBuilder = context.getClassEditorBuilder("org.apache.http.concurrent.BasicFuture"); classEditorBuilder.injectMetadata(METADATA_ASYNC_TRACE_ID); - + MethodEditorBuilder methodEditorBuilder = classEditorBuilder.editMethod("get"); methodEditorBuilder.property(MethodEditorProperty.IGNORE_IF_NOT_EXIST); - methodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.BasicFutureGetInterceptor"); + methodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.BasicFutureMethodInterceptor"); MethodEditorBuilder getMethodEditorBuilder = classEditorBuilder.editMethod("get", "long", "java.util.concurrent.TimeUnit"); getMethodEditorBuilder.property(MethodEditorProperty.IGNORE_IF_NOT_EXIST); - getMethodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.BasicFutureGetInterceptor"); + getMethodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.BasicFutureMethodInterceptor"); MethodEditorBuilder completedMethodEditorBuilder = classEditorBuilder.editMethod("completed", "java.lang.Object"); completedMethodEditorBuilder.property(MethodEditorProperty.IGNORE_IF_NOT_EXIST); - completedMethodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.BasicFutureCompletedInterceptor"); + completedMethodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.BasicFutureMethodInterceptor"); MethodEditorBuilder failMethodEditorBuilder = classEditorBuilder.editMethod("failed", "java.lang.Exception"); failMethodEditorBuilder.property(MethodEditorProperty.IGNORE_IF_NOT_EXIST); - failMethodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.BasicFutureFailedInterceptor"); + failMethodEditorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.httpclient4.interceptor.BasicFutureMethodInterceptor"); context.addClassEditor(classEditorBuilder.build()); } diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4TypeProvider.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4TypeProvider.java index 3be6e1e48..c74bd21d3 100644 --- a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4TypeProvider.java +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4TypeProvider.java @@ -18,6 +18,11 @@ package com.navercorp.pinpoint.plugin.httpclient4; import com.navercorp.pinpoint.common.plugin.TypeProvider; import com.navercorp.pinpoint.common.plugin.TypeSetupContext; +/** + * + * @author jaehong.kim + * + */ public class HttpClient4TypeProvider implements TypeProvider, HttpClient4Constants{ @Override diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AbstractHttpRequestExecute.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AbstractHttpRequestExecute.java index 2a13dd3bd..63d94b65a 100644 --- a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AbstractHttpRequestExecute.java +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AbstractHttpRequestExecute.java @@ -47,6 +47,7 @@ import java.io.Reader; /** * @author emeroad + * @author jaehong.kim */ public abstract class AbstractHttpRequestExecute implements TraceContextSupport, ByteCodeMethodDescriptorSupport, SimpleAroundInterceptor { diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AsyncInternalClientExecuteInterceptor.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AsyncInternalClientExecuteInterceptor.java index d81ba931e..4a6117d23 100644 --- a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AsyncInternalClientExecuteInterceptor.java +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AsyncInternalClientExecuteInterceptor.java @@ -81,6 +81,7 @@ import com.navercorp.pinpoint.bootstrap.pair.NameIntValuePair; * * * @author netspider + * @author jaehong.kim * */ public class AsyncInternalClientExecuteInterceptor extends AbstractHttpRequestExecute implements TargetClassLoader { diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/BasicFutureMethodInterceptor.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/BasicFutureMethodInterceptor.java new file mode 100644 index 000000000..6f4bbbf90 --- /dev/null +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/BasicFutureMethodInterceptor.java @@ -0,0 +1,124 @@ +/* + * 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.httpclient4.interceptor; + +import com.navercorp.pinpoint.bootstrap.MetadataAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncTraceId; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.ByteCodeMethodDescriptorSupport; +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.Cached; +import com.navercorp.pinpoint.bootstrap.plugin.Name; +import com.navercorp.pinpoint.common.AnnotationKey; +import com.navercorp.pinpoint.common.ServiceType; +import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4Constants; + +/** + * + * @author netspider + * @author jaehong.kim + * + */ +public class BasicFutureMethodInterceptor implements SimpleAroundInterceptor, ByteCodeMethodDescriptorSupport, HttpClient4Constants { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor descriptor; + private MetadataAccessor asyncTraceIdAccessor; + + public BasicFutureMethodInterceptor(TraceContext traceContext, @Cached MethodDescriptor methodDescriptor, @Name(METADATA_ASYNC_TRACE_ID) MetadataAccessor asyncTraceIdAccessor) { + this.traceContext = traceContext; + this.descriptor = methodDescriptor; + this.asyncTraceIdAccessor = asyncTraceIdAccessor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (!asyncTraceIdAccessor.isApplicable(target) || asyncTraceIdAccessor.get(target) == null) { + logger.debug("Not found asynchronous invocation metadata"); + return; + } + + final AsyncTraceId asyncTraceId = asyncTraceIdAccessor.get(target); + boolean async = false; + Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + trace = traceContext.continueAsyncTraceObject(asyncTraceId, asyncTraceId.getAsyncId(), asyncTraceId.getSpanStartTime()); + if (trace == null) { + logger.warn("Failed to continue async trace. 'result is null'"); + return; + } + async = true; + if(isDebug) { + logger.debug("Continue async trace {} [{}]", asyncTraceId, Thread.currentThread().getName()); + } + + } + + logger.debug("TraceBlockBegin [{}]", Thread.currentThread().getName()); + trace.traceBlockBegin(); + trace.markBeforeTime(); + trace.recordServiceType(ServiceType.HTTP_CLIENT_INTERNAL); + if(async) { + trace.recordAttribute(AnnotationKey.ASYNC, ""); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args); + } + + Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + logger.debug("Not found trace"); + return; + } + + try { + trace.recordApi(descriptor); + trace.recordException(throwable); + trace.markAfterTime(); + } finally { + trace.traceBlockEnd(); + if(trace.isAsync() && trace.isRootStack()) { + trace.traceRootBlockEnd(); + traceContext.detachTraceObject(); + if(isDebug) { + logger.debug("End async trace {} [{}]", trace.getTraceId(), Thread.currentThread().getName()); + } + } + } + } + + @Override + public void setMethodDescriptor(MethodDescriptor descriptor) { + this.descriptor = descriptor; + traceContext.cacheApi(descriptor); + } +} \ No newline at end of file diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AsyncClientExecuteInterceptor.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/CloseableHttpAsyncClientExecuteMethodWithHttpRequestInterceptor.java similarity index 86% rename from plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AsyncClientExecuteInterceptor.java rename to plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/CloseableHttpAsyncClientExecuteMethodWithHttpRequestInterceptor.java index 5903b6da1..b75539a4d 100644 --- a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/AsyncClientExecuteInterceptor.java +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/CloseableHttpAsyncClientExecuteMethodWithHttpRequestInterceptor.java @@ -45,12 +45,13 @@ import com.navercorp.pinpoint.bootstrap.pair.NameIntValuePair; * * * @author netspider + * @author jaehong.kim * */ -public class AsyncClientExecuteInterceptor extends AbstractHttpRequestExecute implements TargetClassLoader { +public class CloseableHttpAsyncClientExecuteMethodWithHttpRequestInterceptor extends AbstractHttpRequestExecute implements TargetClassLoader { - public AsyncClientExecuteInterceptor() { - super(AsyncClientExecuteInterceptor.class); + public CloseableHttpAsyncClientExecuteMethodWithHttpRequestInterceptor() { + super(CloseableHttpAsyncClientExecuteMethodWithHttpRequestInterceptor.class); } @Override