diff --git a/agent/pom.xml b/agent/pom.xml index 339010b8e..6273e10ae 100644 --- a/agent/pom.xml +++ b/agent/pom.xml @@ -1,138 +1,143 @@ - 4.0.0 - - com.navercorp.pinpoint - pom - 1.5.0-SNAPSHOT - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + 4.0.0 + + com.navercorp.pinpoint + pom + 1.5.0-SNAPSHOT + - pinpoint-agent - pinpoint-agent-distribution + pinpoint-agent + pinpoint-agent-distribution - - jar + + jar - - - com.navercorp.pinpoint - pinpoint-profiler - - - com.navercorp.pinpoint - pinpoint-profiler-optional - + + + com.navercorp.pinpoint + pinpoint-profiler + + + com.navercorp.pinpoint + pinpoint-profiler-optional + - - - com.navercorp.pinpoint - pinpoint-plugins - zip - runtime - + + + com.navercorp.pinpoint + pinpoint-plugins + zip + runtime + - - - com.navercorp.pinpoint - pinpoint-test - test - - - org.springframework - spring-test - test - - - org.springframework - spring-context - test - - - com.google.code.gson - gson - 2.3.1 - test - - - net.sf.json-lib - json-lib - 2.3 - jdk15 - test - - - com.fasterxml.jackson.core - jackson-databind - test - - - org.codehaus.jackson - jackson-mapper-asl - test - - + + + com.navercorp.pinpoint + pinpoint-test + test + + + org.springframework + spring-test + test + + + org.springframework + spring-context + test + + + com.google.code.gson + gson + 2.3.1 + test + + + net.sf.json-lib + json-lib + 2.3 + jdk15 + test + + + com.fasterxml.jackson.core + jackson-databind + test + + + org.codehaus.jackson + jackson-mapper-asl + test + + + com.google.http-client + google-http-client + test + + - - - - ${basedir}/src/main/java - - **/*.java - - - - true - ${basedir}/src/main/resources - - - ${basedir}/src/main/resources-${env} - - + + + + ${basedir}/src/main/java + + **/*.java + + + + true + ${basedir}/src/main/resources + + + ${basedir}/src/main/resources-${env} + + - - - org.apache.maven.plugins - maven-failsafe-plugin - 2.18.1 - - - integration-test - - integration-test - - - - verify - - verify - - - - - - org.apache.maven.plugins - maven-assembly-plugin - 2.5.3 - - - src/assembly/distribution.xml - - ${project.build.directory} - false - - - - create-distribution - package - - single - - - - - - + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.18.1 + + + integration-test + + integration-test + + + + verify + + verify + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.5.3 + + + src/assembly/distribution.xml + + ${project.build.directory} + false + + + + create-distribution + package + + single + + + + + + diff --git a/agent/src/main/resources/pinpoint.config b/agent/src/main/resources/pinpoint.config index 18b96b868..eed827f8e 100644 --- a/agent/src/main/resources/pinpoint.config +++ b/agent/src/main/resources/pinpoint.config @@ -241,4 +241,11 @@ profiler.log4j.logging.transactioninfo=false ########################################################### # logback (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) ########################################################### -profiler.logback.logging.transactioninfo=false \ No newline at end of file +profiler.logback.logging.transactioninfo=false + +########################################################### +# google httpclient +########################################################### +profiler.google.httpclient.enable=true +profiler.google.httpclient.async=true +profiler.google.httpclient.async.innerclassname.max=3 \ No newline at end of file diff --git a/plugins/google-httpclient/.gitignore b/plugins/google-httpclient/.gitignore new file mode 100644 index 000000000..8c2d47305 --- /dev/null +++ b/plugins/google-httpclient/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/google-httpclient/clover.license b/plugins/google-httpclient/clover.license new file mode 100644 index 000000000..569fa6175 --- /dev/null +++ b/plugins/google-httpclient/clover.license @@ -0,0 +1,5 @@ +RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC +mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 + + com.navercorp.pinpoint + pom + ../.. + 1.5.0-SNAPSHOT + + + pinpoint-google-httpclient-plugin + pinpoint-google-httpclient-plugin + jar + + + + com.navercorp.pinpoint + pinpoint-bootstrap + provided + + + + + + com.google.http-client + google-http-client + provided + + + diff --git a/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientConstants.java b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientConstants.java new file mode 100644 index 000000000..b6db4acbe --- /dev/null +++ b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientConstants.java @@ -0,0 +1,27 @@ +/* + * 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.google.httpclient; + + +/** + * + * @author jaehong.kim + * + */ +public interface HttpClientConstants { + public static final String METADATA_ASYNC_TRACE_ID = "asyncTraceId"; + public static final String EXECUTE_ASYNC_SCOPE = "ExecuteAsyncScope"; +} diff --git a/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientPlugin.java b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientPlugin.java new file mode 100644 index 000000000..5b5fca495 --- /dev/null +++ b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientPlugin.java @@ -0,0 +1,113 @@ +/* + * 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.google.httpclient; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +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.ProfilerPluginContext; +import com.navercorp.pinpoint.bootstrap.plugin.transformer.ClassCondition; +import com.navercorp.pinpoint.bootstrap.plugin.transformer.ClassFileTransformerBuilder; +import com.navercorp.pinpoint.bootstrap.plugin.transformer.ConditionalClassFileTransformerBuilder; +import com.navercorp.pinpoint.bootstrap.plugin.transformer.ConditionalClassFileTransformerSetup; +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; + +/** + * @author jaehong.kim + * + */ +public class HttpClientPlugin implements ProfilerPlugin, HttpClientConstants { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + @Override + public void setup(ProfilerPluginContext context) { + final HttpClientPluginConfig config = new HttpClientPluginConfig(context.getConfig()); + logger.debug("[GoogleHttpClient] Initialized config={}", config); + + if (!config.isEnable()) { + return; + } + + logger.debug("[GoogleHttpClient] Add HttpRequest class."); + addHttpRequestClass(context, config); + + if (config.isAsync()) { + final int max = config.getMaxAnonymousInnerClassNameNumber(); + for (int i = 1; i <= max; i++) { + final String targetClassName = "com.google.api.client.http.HttpRequest$" + i; + logger.debug("[GoogleHttpClient] Add {} class.", targetClassName); + addHttpRequestExecuteAsyncMethodInnerClass(context, targetClassName); + } + } + } + + private void addHttpRequestClass(ProfilerPluginContext context, HttpClientPluginConfig config) { + final ClassFileTransformerBuilder classBuilder = context.getClassFileTransformerBuilder("com.google.api.client.http.HttpRequest"); + + MethodTransformerBuilder executeMethodBuilder = classBuilder.editMethod("execute"); + executeMethodBuilder.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); + executeMethodBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.google.httpclient.interceptor.HttpRequestExecuteMethodInterceptor"); + + if (config.isAsync()) { + MethodTransformerBuilder executeAsyncMethodBuilder = classBuilder.editMethod("executeAsync", "java.util.concurrent.Executor"); + executeAsyncMethodBuilder.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST); + executeAsyncMethodBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.google.httpclient.interceptor.HttpRequestExecuteAsyncMethodInterceptor"); + } + + context.addClassFileTransformer(classBuilder.build()); + } + + private void addHttpRequestExecuteAsyncMethodInnerClass(ProfilerPluginContext context, String targetClassName) { + final ClassFileTransformerBuilder classBuilder = context.getClassFileTransformerBuilder(targetClassName); + classBuilder.injectMetadata(METADATA_ASYNC_TRACE_ID); + + classBuilder.conditional(new ClassCondition() { + @Override + public boolean check(ProfilerPluginContext context, ClassLoader classLoader, InstrumentClass target) { + if (!target.hasConstructor(new String[] { "com.google.api.client.http.HttpRequest" })) { + return false; + } + + if (!target.hasMethod("call", null, "com.google.api.client.http.HttpResponse")) { + return false; + } + + return true; + } + }, new ConditionalClassFileTransformerSetup() { + @Override + public void setup(ConditionalClassFileTransformerBuilder conditional) { + ConstructorTransformerBuilder constructorBuilder = conditional.editConstructor("com.google.api.client.http.HttpRequest"); + constructorBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.google.httpclient.interceptor.HttpRequestExecuteAsyncMethodInnerClassConstructorInterceptor"); + + MethodTransformerBuilder methodBuilder = conditional.editMethods(new HttpRequestExceuteAsyncMethodInnerClassMethodFilter()); + methodBuilder.exceptionHandler(new MethodTransformerExceptionHandler() { + public void handle(String targetClassName, String targetMethodName, String[] targetMethodParameterTypes, Throwable exception) throws Throwable { + if (logger.isWarnEnabled()) { + logger.warn("[GoogleHttpClient] Unsupported method " + targetClassName + "." + targetMethodName, exception); + } + } + }); + methodBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.google.httpclient.interceptor.HttpRequestExecuteAsyncMethodInnerClassCallMethodInterceptor"); + } + }); + context.addClassFileTransformer(classBuilder.build()); + } +} \ No newline at end of file diff --git a/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientPluginConfig.java b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientPluginConfig.java new file mode 100644 index 000000000..3026b0a66 --- /dev/null +++ b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientPluginConfig.java @@ -0,0 +1,61 @@ +/* + * 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.google.httpclient; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +/** + * + * @author jaehong.kim + * + */ +public class HttpClientPluginConfig { + + private final boolean enable; + private final boolean async; + private final int maxAnonymousInnerClassNameNumber; + + public HttpClientPluginConfig(ProfilerConfig src) { + enable = src.readBoolean("profiler.google.httpclient.enable", true); + async = src.readBoolean("profiler.google.httpclient.async", true); + maxAnonymousInnerClassNameNumber = src.readInt("profiler.google.httpclient.async.innerclassname.max", 3); + } + + public boolean isEnable() { + return enable; + } + + public boolean isAsync() { + return async; + } + + public int getMaxAnonymousInnerClassNameNumber() { + return maxAnonymousInnerClassNameNumber; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("{enable="); + builder.append(enable); + builder.append(", async="); + builder.append(async); + builder.append(", maxAnonymousInnerClassNameNumber="); + builder.append(maxAnonymousInnerClassNameNumber); + builder.append("}"); + return builder.toString(); + } +} \ No newline at end of file diff --git a/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientTypeProvider.java b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientTypeProvider.java new file mode 100644 index 000000000..805485a38 --- /dev/null +++ b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpClientTypeProvider.java @@ -0,0 +1,31 @@ +/* + * 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.google.httpclient; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * + * @author jaehong.kim + * + */ +public class HttpClientTypeProvider implements TraceMetadataProvider, HttpClientConstants{ + + @Override + public void setup(TraceMetadataSetupContext context) { + } +} diff --git a/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpRequestExceuteAsyncMethodInnerClassMethodFilter.java b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpRequestExceuteAsyncMethodInnerClassMethodFilter.java new file mode 100644 index 000000000..67a7e3338 --- /dev/null +++ b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpRequestExceuteAsyncMethodInnerClassMethodFilter.java @@ -0,0 +1,50 @@ +/* + * 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.google.httpclient; + +import java.lang.reflect.Modifier; + +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter; +import com.navercorp.pinpoint.bootstrap.instrument.MethodInfo; + +/** + * + * @author jaehong.kim + * + */ +public class HttpRequestExceuteAsyncMethodInnerClassMethodFilter implements MethodFilter { + private static final int SYNTHETIC = 0x00001000; + + @Override + public boolean accept(MethodInfo method) { + final int modifiers = method.getModifiers(); + + if (isSynthetic(modifiers) || !Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers) || Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + return REJECT; + } + + final String name = method.getName(); + if (name.equals("call")) { + return ACCEPT; + } + + return REJECT; + } + + private boolean isSynthetic(int mod) { + return (mod & SYNTHETIC) != 0; + } +} \ No newline at end of file diff --git a/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteAsyncMethodInnerClassCallMethodInterceptor.java b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteAsyncMethodInnerClassCallMethodInterceptor.java new file mode 100644 index 000000000..9db7f3648 --- /dev/null +++ b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteAsyncMethodInnerClassCallMethodInterceptor.java @@ -0,0 +1,49 @@ +/* + * 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.google.httpclient.interceptor; + +import com.navercorp.pinpoint.bootstrap.MetadataAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncTraceId; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanAsyncEventSimpleAroundInterceptor; +import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.google.httpclient.HttpClientConstants; + +/** + * + * @author jaehong.kim + * + */ +public class HttpRequestExecuteAsyncMethodInnerClassCallMethodInterceptor extends SpanAsyncEventSimpleAroundInterceptor { + + public HttpRequestExecuteAsyncMethodInnerClassCallMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor, @Name(HttpClientConstants.METADATA_ASYNC_TRACE_ID) MetadataAccessor asyncTraceIdAccessor) { + super(traceContext, descriptor, asyncTraceIdAccessor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncTraceId asyncTraceId, Object target, Object[] args) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(ServiceType.HTTP_CLIENT_INTERNAL); + recorder.recordException(throwable); + } +} \ No newline at end of file diff --git a/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteAsyncMethodInnerClassConstructorInterceptor.java b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteAsyncMethodInnerClassConstructorInterceptor.java new file mode 100644 index 000000000..a0fea4751 --- /dev/null +++ b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteAsyncMethodInnerClassConstructorInterceptor.java @@ -0,0 +1,88 @@ +/* + * 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.google.httpclient.interceptor; + +import com.navercorp.pinpoint.bootstrap.MetadataAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncTraceId; +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.bootstrap.plugin.annotation.Name; +import com.navercorp.pinpoint.plugin.google.httpclient.HttpClientConstants; + +/** + * + * @author jaehong.kim + * + */ +@Group(value = HttpClientConstants.EXECUTE_ASYNC_SCOPE, executionPoint = ExecutionPolicy.ALWAYS) +public class HttpRequestExecuteAsyncMethodInnerClassConstructorInterceptor implements SimpleAroundInterceptor, HttpClientConstants { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final MetadataAccessor asyncTraceIdAccessor; + private InterceptorGroup interceptorGroup; + + public HttpRequestExecuteAsyncMethodInnerClassConstructorInterceptor(TraceContext traceContext, MethodDescriptor descriptor, @Name(HttpClientConstants.METADATA_ASYNC_TRACE_ID) MetadataAccessor asyncTraceIdAccessor, InterceptorGroup interceptorGroup) { + this.asyncTraceIdAccessor = asyncTraceIdAccessor; + this.interceptorGroup = interceptorGroup; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + try { + if (!validate(target, args)) { + return; + } + + InterceptorGroupInvocation transaction = interceptorGroup.getCurrentInvocation(); + if(transaction != null && transaction.getAttachment() != null) { + AsyncTraceId asyncTraceId = (AsyncTraceId) transaction.getAttachment(); + asyncTraceIdAccessor.set(target, asyncTraceId); + // clear. + transaction.removeAttachment(); + } + } catch (Throwable t) { + logger.warn("Failed to before process. {}", t.getMessage(), t); + } + } + + private boolean validate(final Object target, final Object[] args) { + if (!asyncTraceIdAccessor.isApplicable(target)) { + logger.debug("Invalid target object. Need metadata accessor({}).", METADATA_ASYNC_TRACE_ID); + return false; + } + + return true; + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args); + } + } +} \ No newline at end of file diff --git a/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteAsyncMethodInterceptor.java b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteAsyncMethodInterceptor.java new file mode 100644 index 000000000..2f5011771 --- /dev/null +++ b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteAsyncMethodInterceptor.java @@ -0,0 +1,110 @@ +/* + * 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.google.httpclient.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.AsyncTraceId; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +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.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.google.httpclient.HttpClientConstants; + +/** + * + * @author jaehong.kim + * + */ +@Group(value = HttpClientConstants.EXECUTE_ASYNC_SCOPE, executionPoint = ExecutionPolicy.ALWAYS) +public class HttpRequestExecuteAsyncMethodInterceptor implements SimpleAroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor methodDescriptor; + private InterceptorGroup interceptorGroup; + + public HttpRequestExecuteAsyncMethodInterceptor(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; + } + + SpanEventRecorder recorder = trace.traceBlockBegin(); + try { + // set asynchronous trace + final AsyncTraceId asyncTraceId = trace.getAsyncTraceId(); + recorder.recordNextAsyncId(asyncTraceId.getAsyncId()); + + // set async id. + InterceptorGroupInvocation transaction = interceptorGroup.getCurrentInvocation(); + if (transaction != null) { + transaction.setAttachment(asyncTraceId); + if (isDebug) { + logger.debug("Set asyncTraceId metadata {}", asyncTraceId); + } + } + } 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, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(ServiceType.HTTP_CLIENT_INTERNAL); + recorder.recordException(throwable); + + // remove async id. + InterceptorGroupInvocation transaction = interceptorGroup.getCurrentInvocation(); + if (transaction != null) { + // clear + transaction.removeAttachment(); + } + } finally { + trace.traceBlockEnd(); + } + } +} \ No newline at end of file diff --git a/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteMethodInterceptor.java b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteMethodInterceptor.java new file mode 100644 index 000000000..21f5aff34 --- /dev/null +++ b/plugins/google-httpclient/src/main/java/com/navercorp/pinpoint/plugin/google/httpclient/interceptor/HttpRequestExecuteMethodInterceptor.java @@ -0,0 +1,45 @@ +/* + * 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.google.httpclient.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.common.trace.ServiceType; + +/** + * + * @author jaehong.kim + * + */ +public class HttpRequestExecuteMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + public HttpRequestExecuteMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(ServiceType.HTTP_CLIENT_INTERNAL); + recorder.recordException(throwable); + } +} \ No newline at end of file diff --git a/plugins/google-httpclient/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/google-httpclient/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000..0d80403d7 --- /dev/null +++ b/plugins/google-httpclient/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.google.httpclient.HttpClientPlugin \ No newline at end of file diff --git a/plugins/google-httpclient/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/google-httpclient/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000..2342d2d87 --- /dev/null +++ b/plugins/google-httpclient/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.google.httpclient.HttpClientTypeProvider \ No newline at end of file diff --git a/plugins/google-httpclient/src/test/resources/pinpoint.config b/plugins/google-httpclient/src/test/resources/pinpoint.config new file mode 100644 index 000000000..4530cef5b --- /dev/null +++ b/plugins/google-httpclient/src/test/resources/pinpoint.config @@ -0,0 +1,213 @@ +# +# Pinpoint agent configuration +# + +########################################################### +# Collector server # +########################################################### +profiler.collector.ip=127.0.0.1 + +# placeHolder support "${key}" +profiler.collector.span.ip=${profiler.collector.ip} +profiler.collector.span.port=9996 + +# placeHolder support "${key}" +profiler.collector.stat.ip=${profiler.collector.ip} +profiler.collector.stat.port=9995 + +# placeHolder support "${key}" +profiler.collector.tcp.ip=${profiler.collector.ip} +profiler.collector.tcp.port=9994 + + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +profiler.jvm.collect.interval=1000 + +profiler.sampling.enable=true +profiler.sampling.rate=1 + +profiler.io.buffering.enable=true +profiler.io.buffering.buffersize=20 + + + +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 +profiler.spandatasender.chunk.size=16384 + +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 +profiler.statdatasender.chunk.size=16384 + +profiler.agentInfo.send.retry.interval=300000 + +profiler.tcpdatasender.command.accept.enable=true + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + + +########################################################### +# user defined classes # +########################################################### +profiler.include=com.navercorp.pinpoint.testweb.controller.*,com.navercorp.pinpoint.testweb.MyClass + +########################################################### +# TOMCAT # +########################################################### +profiler.tomcat.hidepinpointheader=true +#naver standard l7 check +profiler.tomcat.excludeurl=/monitor/l7check.html +#profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html + +########################################################### +# 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 Jtds +# +profiler.jdbc.jtds=true +profiler.jdbc.jtds.setautocommit=true +profiler.jdbc.jtds.commit=true +profiler.jdbc.jtds.rollback=true + +# +# 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 +profiler.apache.httpclient4.cookie.dumptype=ALWAYS +profiler.apache.httpclient4.cookie.sampling.rate=1 + +profiler.apache.httpclient4.entity=true +profiler.apache.httpclient4.entity.dumptype=ALWAYS +profiler.apache.httpclient4.entity.sampling.rate=1 + +# Can profile status code value +profiler.apache.httpclient4.entity.statuscode=true + +# Not supported yet +#profiler.apache.nio.httpclient4=true + + +########################################################### +# JDK HTTPURLConnection # +########################################################### +profiler.jdk.httpurlconnection=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 + + +########################################################### +# 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 + +########################################################### +# redis # +########################################################### +profiler.redis=true +profiler.redis.pipeline=true + +########################################################### +# nBase-ARC # +########################################################### +profiler.nbase_arc=true +profiler.nbase_arc.pipeline=true + +########################################################### +# spring-beans +########################################################### +profiler.spring.beans=false +profiler.spring.beans.name.pattern= +profiler.spring.beans.class.pattern= +profiler.spring.beans.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository + + +########################################################### +# google httpclient +########################################################### +profiler.google.httpclient.enable=true +profiler.google.httpclient.async=true +profiler.google.httpclient.async.innerclassname.max=3 \ No newline at end of file diff --git a/plugins/pom.xml b/plugins/pom.xml index 1f50dee20..431dad2d2 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -25,6 +25,7 @@ thrift user arcus + google-httpclient @@ -93,6 +94,11 @@ pinpoint-arcus-plugin ${project.version} + + com.navercorp.pinpoint + pinpoint-google-httpclient-plugin + ${project.version} + diff --git a/pom.xml b/pom.xml index c929c1155..808cc9a7c 100644 --- a/pom.xml +++ b/pom.xml @@ -455,6 +455,11 @@ 3.1 + + com.google.http-client + google-http-client + 1.20.0 + redis.clients