Skip to content

Commit

Permalink
add OkHttp plugin.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaehong-kim committed Sep 9, 2015
1 parent 2e87485 commit de7ec85
Show file tree
Hide file tree
Showing 18 changed files with 957 additions and 0 deletions.
5 changes: 5 additions & 0 deletions plugins/okhttp/.gitignore
@@ -0,0 +1,5 @@
/target/
/.settings/
/.classpath
/.project
/*.iml
5 changes: 5 additions & 0 deletions plugins/okhttp/clover.license
@@ -0,0 +1,5 @@
RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC
mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF<mV
RmmnSVOqOMnOnMMrmMqwXomoroNrqPNRrPSsWwtUxXuUU
sRONqpnmqmUUnqonmstsmmmmmUUnqonmstsmmmmmUUGfk
mlfkqUUnmmmm
30 changes: 30 additions & 0 deletions plugins/okhttp/pom.xml
@@ -0,0 +1,30 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pom</artifactId>
<relativePath>../..</relativePath>
<version>1.5.0-SNAPSHOT</version>
</parent>

<artifactId>pinpoint-okhttp-plugin</artifactId>
<name>pinpoint-okhttp-plugin</name>
<packaging>jar</packaging>

<dependencies>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-bootstrap-core</artifactId>
<scope>provided</scope>
</dependency>


<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,10 @@
package com.navercorp.pinpoint.plugin.okhttp;

import com.squareup.okhttp.Connection;

/**
* Created by nbp on 2015-09-08.
*/
public interface ConnectionGetter {
public Connection _$PINPOINT$_getConnection();
}
@@ -0,0 +1,10 @@
package com.navercorp.pinpoint.plugin.okhttp;

import com.squareup.okhttp.HttpUrl;

/**
* Created by nbp on 2015-09-08.
*/
public interface HttpUrlGetter {
public HttpUrl _$PINPOINT$_getHttpUrl();
}
@@ -0,0 +1,41 @@
/*
* 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.okhttp;

import static com.navercorp.pinpoint.common.trace.HistogramSchema.*;
import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS;

import com.navercorp.pinpoint.common.trace.ServiceType;


/**
*
* @author jaehong.kim
*
*/
public interface OkHttpConstants {
public static final ServiceType OK_HTTP_CLIENT = ServiceType.of(9058, "OK_HTTP_CLIENT", NORMAL_SCHEMA, RECORD_STATISTICS);
public static final ServiceType OK_HTTP_CLIENT_INTERNAL = ServiceType.of(9059, "OK_HTTP_CLIENT_INTERNAL", "OK_HTTP_CLIENT", NORMAL_SCHEMA);

public static final String BASIC_METHOD_INTERCEPTOR = "com.navercorp.pinpoint.bootstrap.interceptor.BasicMethodInterceptor";
public static final String METADATA_ASYNC_TRACE_ID = "com.navercorp.pinpoint.bootstrap.interceptor.AsyncTraceIdAccessor";
public static final String SEND_REQUEST_SCOPE = "SendRequestScope";

public static final String FIELD_USER_REQUEST = "userRequest";
public static final String FIELD_USER_RESPONSE = "userResponse";
public static final String FIELD_CONNECTION = "connection";
public static final String FIELD_HTTP_URL = "url";
}
@@ -0,0 +1,160 @@
/*
* 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.okhttp;

import java.security.ProtectionDomain;

import com.navercorp.pinpoint.bootstrap.instrument.*;
import com.navercorp.pinpoint.bootstrap.interceptor.AsyncTraceIdAccessor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginInstrumentContext;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext;
import com.navercorp.pinpoint.bootstrap.plugin.transformer.PinpointClassFileTransformer;

/**
* @author jaehong.kim
*
*/
public class OkHttpPlugin implements ProfilerPlugin, OkHttpConstants {
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());

@Override
public void setup(ProfilerPluginSetupContext context) {
final OkHttpPluginConfig config = new OkHttpPluginConfig(context.getConfig());
logger.debug("[OkHttp] Initialized config={}", config);

logger.debug("[OkHttp] Add Call class.");
addCall(context, config);
logger.debug("[OkHttp] Add Dispatcher class.");
addDispatcher(context, config);
logger.debug("[OkHttp] Add AsyncCall class.");
addAsyncCall(context, config);
addHttpEngine(context, config);
addRequestBuilder(context, config);
}

private void addCall(ProfilerPluginSetupContext context, final OkHttpPluginConfig config) {
context.addClassFileTransformer("com.squareup.okhttp.Call", new PinpointClassFileTransformer() {

@Override
public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer);

for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("execute", "enqueue", "cancel"))) {
method.addInterceptor(BASIC_METHOD_INTERCEPTOR, OK_HTTP_CLIENT_INTERNAL);
}

return target.toBytecode();
}
});
}

private void addDispatcher(ProfilerPluginSetupContext context, final OkHttpPluginConfig config) {
context.addClassFileTransformer("com.squareup.okhttp.Dispatcher", new PinpointClassFileTransformer() {

@Override
public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer);

for(InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("execute", "cancel"))) {
logger.debug("[OkHttp] Add Dispatcher.execute | cancel interceptor.");
method.addInterceptor(BASIC_METHOD_INTERCEPTOR, OK_HTTP_CLIENT_INTERNAL);
}
InstrumentMethod enqueueMethod = target.getDeclaredMethod("enqueue", "com.squareup.okhttp.Call$AsyncCall");
if(enqueueMethod != null) {
logger.debug("[OkHttp] Add Dispatcher.enqueue interceptor.");
enqueueMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.interceptor.DispatcherEnqueueMethodInterceptor");
}

return target.toBytecode();
}
});
}

private void addAsyncCall(ProfilerPluginSetupContext context, final OkHttpPluginConfig config) {
context.addClassFileTransformer("com.squareup.okhttp.Call$AsyncCall", new PinpointClassFileTransformer() {

@Override
public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer);
target.addField(AsyncTraceIdAccessor.class.getName());

InstrumentMethod executeMethod = target.getDeclaredMethod("execute");
if(executeMethod != null) {
logger.debug("[OkHttp] Add AsyncCall.execute interceptor.");
executeMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.interceptor.AsyncCallExecuteMethodInterceptor");
}

return target.toBytecode();
}
});
}

private void addHttpEngine(ProfilerPluginSetupContext context, final OkHttpPluginConfig config) {
context.addClassFileTransformer("com.squareup.okhttp.internal.http.HttpEngine", new PinpointClassFileTransformer() {

@Override
public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer);
target.addGetter(UserRequestGetter.class.getName(), FIELD_USER_REQUEST);
target.addGetter(UserResponseGetter.class.getName(), FIELD_USER_RESPONSE);
target.addGetter(ConnectionGetter.class.getName(), FIELD_CONNECTION);

InstrumentMethod sendRequestMethod = target.getDeclaredMethod("sendRequest");
if(sendRequestMethod != null) {
logger.debug("[OkHttp] Add HttpEngine.sendRequest interceptor.");
sendRequestMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.interceptor.HttpEngineSendRequestMethodInterceptor");
}

InstrumentMethod connectMethod = target.getDeclaredMethod("connect");
if(connectMethod != null) {
logger.debug("[OkHttp] Add HttpEngine.connect interceptor.");
connectMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.interceptor.HttpEngineConnectMethodInterceptor");
}

InstrumentMethod readResponseMethod = target.getDeclaredMethod("readResponse");
if(readResponseMethod != null) {
logger.debug("[OkHttp] Add HttpEngine.connect interceptor.");
readResponseMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.interceptor.HttpEngineReadResponseMethodInterceptor");
}

return target.toBytecode();
}
});
}

private void addRequestBuilder(ProfilerPluginSetupContext context, final OkHttpPluginConfig config) {
context.addClassFileTransformer("com.squareup.okhttp.Request$Builder", new PinpointClassFileTransformer() {

@Override
public byte[] transform(ProfilerPluginInstrumentContext instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer);
target.addGetter(HttpUrlGetter.class.getName(), FIELD_HTTP_URL);

InstrumentMethod buildMethod = target.getDeclaredMethod("build");
if(buildMethod != null) {
logger.debug("[OkHttp] Add Request.Builder.build interceptor.");
buildMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.interceptor.RequestBuilderBuildMethodInterceptor");
}

return target.toBytecode();
}
});
}

}
@@ -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.okhttp;

import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig;

/**
*
* @author jaehong.kim
*
*/
public class OkHttpPluginConfig {

private final boolean async;

public OkHttpPluginConfig(ProfilerConfig src) {
async = src.readBoolean("profiler.google.httpclient.async", true);
}

public boolean isAsync() {
return async;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("{async=");
builder.append(async);
builder.append("}");
return builder.toString();
}
}
@@ -0,0 +1,35 @@
/*
* 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.okhttp;

import com.navercorp.pinpoint.common.trace.AnnotationKey;
import com.navercorp.pinpoint.common.trace.AnnotationKeyMatcher;
import com.navercorp.pinpoint.common.trace.TraceMetadataProvider;
import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext;

/**
*
* @author jaehong.kim
*
*/
public class OkHttpTypeProvider implements TraceMetadataProvider, OkHttpConstants {

@Override
public void setup(TraceMetadataSetupContext context) {
context.addServiceType(OK_HTTP_CLIENT, new AnnotationKeyMatcher.ExactMatcher(AnnotationKey.HTTP_URL));
context.addServiceType(OK_HTTP_CLIENT_INTERNAL, new AnnotationKeyMatcher.ExactMatcher(AnnotationKey.HTTP_INTERNAL_DISPLAY));
}
}
@@ -0,0 +1,10 @@
package com.navercorp.pinpoint.plugin.okhttp;

import com.squareup.okhttp.Request;

/**
* Created by nbp on 2015-09-08.
*/
public interface UserRequestGetter {
public Request _$PINPOINT$_getUserRequest();
}
@@ -0,0 +1,10 @@
package com.navercorp.pinpoint.plugin.okhttp;

import com.squareup.okhttp.Request;

/**
* Created by nbp on 2015-09-08.
*/
public interface UserRequestSetter {
public Request _$PINPOINT$_getUserRequest();
}
@@ -0,0 +1,10 @@
package com.navercorp.pinpoint.plugin.okhttp;

import com.squareup.okhttp.Response;

/**
* Created by nbp on 2015-09-08.
*/
public interface UserResponseGetter {
public Response _$PINPOINT$_getUserResponse();
}

0 comments on commit de7ec85

Please sign in to comment.