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