diff --git a/plugins/okhttp/.gitignore b/plugins/okhttp/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/okhttp/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/okhttp/clover.license b/plugins/okhttp/clover.license new file mode 100644 index 000000000000..569fa6175b4c --- /dev/null +++ b/plugins/okhttp/clover.license @@ -0,0 +1,5 @@ +RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC +mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 + + com.navercorp.pinpoint + pom + ../.. + 1.5.0-SNAPSHOT + + + pinpoint-okhttp-plugin + pinpoint-okhttp-plugin + jar + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + + + + com.squareup.okhttp + okhttp + provided + + + diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/ConnectionGetter.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/ConnectionGetter.java new file mode 100644 index 000000000000..1a0a4b995c60 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/ConnectionGetter.java @@ -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(); +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/HttpUrlGetter.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/HttpUrlGetter.java new file mode 100644 index 000000000000..e1ddcabfcf41 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/HttpUrlGetter.java @@ -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(); +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpConstants.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpConstants.java new file mode 100644 index 000000000000..1ea9686644c3 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpConstants.java @@ -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"; +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPlugin.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPlugin.java new file mode 100644 index 000000000000..64a5090724f6 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPlugin.java @@ -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(); + } + }); + } + +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPluginConfig.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPluginConfig.java new file mode 100644 index 000000000000..695164d63db5 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPluginConfig.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.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(); + } +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpTypeProvider.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpTypeProvider.java new file mode 100644 index 000000000000..c5e1a197dc6b --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpTypeProvider.java @@ -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)); + } +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/UserRequestGetter.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/UserRequestGetter.java new file mode 100644 index 000000000000..071e60f9f890 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/UserRequestGetter.java @@ -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(); +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/UserRequestSetter.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/UserRequestSetter.java new file mode 100644 index 000000000000..584edf420e10 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/UserRequestSetter.java @@ -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(); +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/UserResponseGetter.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/UserResponseGetter.java new file mode 100644 index 000000000000..8365456d6df4 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/UserResponseGetter.java @@ -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(); +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/AsyncCallExecuteMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/AsyncCallExecuteMethodInterceptor.java new file mode 100644 index 000000000000..b9ebcd7c5d21 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/AsyncCallExecuteMethodInterceptor.java @@ -0,0 +1,46 @@ +/* + * 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.interceptor; + +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.plugin.okhttp.OkHttpConstants; + +/** + * + * @author jaehong.kim + * + */ +public class AsyncCallExecuteMethodInterceptor extends SpanAsyncEventSimpleAroundInterceptor { + + public AsyncCallExecuteMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @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(OkHttpConstants.OK_HTTP_CLIENT_INTERNAL); + recorder.recordException(throwable); + } +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/DispatcherEnqueueMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/DispatcherEnqueueMethodInterceptor.java new file mode 100644 index 000000000000..8194d7d23585 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/DispatcherEnqueueMethodInterceptor.java @@ -0,0 +1,115 @@ +/* + * 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.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.AsyncTraceIdAccessor; +import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.group.ExecutionPolicy; +import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroup; +import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroupInvocation; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.annotation.Group; +import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; + +/** + * + * @author jaehong.kim + * + */ +public class DispatcherEnqueueMethodInterceptor implements SimpleAroundInterceptor, OkHttpConstants{ + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor methodDescriptor; + private InterceptorGroup interceptorGroup; + + public DispatcherEnqueueMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if(!validate(args)) { + return; + } + + SpanEventRecorder recorder = trace.traceBlockBegin(); + try { + // set asynchronous trace + final AsyncTraceId asyncTraceId = trace.getAsyncTraceId(); + recorder.recordNextAsyncId(asyncTraceId.getAsyncId()); + + // set async id. + ((AsyncTraceIdAccessor)args[0])._$PINPOINT$_setAsyncTraceId(asyncTraceId); + if (isDebug) { + logger.debug("Set asyncTraceId metadata {}", asyncTraceId); + } + } catch (Throwable t) { + logger.warn("Failed to before process. {}", t.getMessage(), t); + } + } + + private boolean validate(Object[] args) { + if (args == null || args.length < 1 || !(args[0] instanceof AsyncTraceIdAccessor)) { + logger.debug("Invalid args[0] object {}. Need field accessor({}).", args, 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); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if(!validate(args)) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(OkHttpConstants.OK_HTTP_CLIENT_INTERNAL); + recorder.recordException(throwable); + } finally { + trace.traceBlockEnd(); + } + } +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/HttpEngineConnectMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/HttpEngineConnectMethodInterceptor.java new file mode 100644 index 000000000000..2240aca4712a --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/HttpEngineConnectMethodInterceptor.java @@ -0,0 +1,56 @@ +/* + * 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.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.AnnotationKey; +import com.navercorp.pinpoint.plugin.okhttp.ConnectionGetter; +import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; +import com.squareup.okhttp.Connection; + +/** + * @author jaehong.kim + */ +public class HttpEngineConnectMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin implements OkHttpConstants { + + public HttpEngineConnectMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + if(target instanceof ConnectionGetter) { + Connection connection = ((ConnectionGetter)target)._$PINPOINT$_getConnection(); + if(connection != null) { + final StringBuilder sb = new StringBuilder(); + sb.append(connection.getRoute().getAddress().getUriHost()).append(":"); + sb.append(connection.getRoute().getAddress().getUriPort()); + recorder.recordAttribute(AnnotationKey.HTTP_INTERNAL_DISPLAY, sb.toString()); + } + } + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(OK_HTTP_CLIENT_INTERNAL); + recorder.recordException(throwable); + } +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/HttpEngineReadResponseMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/HttpEngineReadResponseMethodInterceptor.java new file mode 100644 index 000000000000..81d7826a375d --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/HttpEngineReadResponseMethodInterceptor.java @@ -0,0 +1,115 @@ +/* + * 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.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroup; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.okhttp.ConnectionGetter; +import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; +import com.navercorp.pinpoint.plugin.okhttp.UserRequestGetter; +import com.navercorp.pinpoint.plugin.okhttp.UserResponseGetter; +import com.squareup.okhttp.HttpUrl; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; + +/** + * @author jaehong.kim + */ +public class HttpEngineReadResponseMethodInterceptor implements SimpleAroundInterceptor, OkHttpConstants { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor methodDescriptor; + private InterceptorGroup interceptorGroup; + + public HttpEngineReadResponseMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if (!validate(target)) { + return; + } + + SpanEventRecorder recorder = trace.traceBlockBegin(); + } + + private boolean validate(Object target) { + if (!(target instanceof UserRequestGetter)) { + logger.debug("Invalid target object. Need field accessor({}).", FIELD_USER_REQUEST); + return false; + } + + if (!(target instanceof UserResponseGetter)) { + logger.debug("Invalid target object. Need field accessor({}).", FIELD_USER_RESPONSE); + return false; + } + + if (!(target instanceof ConnectionGetter)) { + logger.debug("Invalid target object. Need field accessor({}).", FIELD_CONNECTION); + return false; + } + + return true; + } + + @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; + } + + if (!validate(target)) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + + Response response = ((UserResponseGetter)target)._$PINPOINT$_getUserResponse(); + if(response != null) { + recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, response.code()); + } + } finally { + trace.traceBlockEnd(); + } + } +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/HttpEngineSendRequestMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/HttpEngineSendRequestMethodInterceptor.java new file mode 100644 index 000000000000..78c779b1d10b --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/HttpEngineSendRequestMethodInterceptor.java @@ -0,0 +1,149 @@ +/* + * 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.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.instrument.AttachmentFactory; +import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor; +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.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.okhttp.ConnectionGetter; +import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; +import com.navercorp.pinpoint.plugin.okhttp.UserRequestGetter; +import com.navercorp.pinpoint.plugin.okhttp.UserResponseGetter; +import com.squareup.okhttp.HttpUrl; +import com.squareup.okhttp.Request; + +/** + * @author jaehong.kim + */ +@Group(OkHttpConstants.SEND_REQUEST_SCOPE) +public class HttpEngineSendRequestMethodInterceptor implements SimpleAroundInterceptor, OkHttpConstants { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor methodDescriptor; + private InterceptorGroup interceptorGroup; + + public HttpEngineSendRequestMethodInterceptor(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.currentRawTraceObject(); + if (trace == null) { + return; + } + + if (!validate(target)) { + return; + } + + SpanEventRecorder recorder = trace.traceBlockBegin(); + try { + final TraceId nextId = trace.getTraceId().getNextTraceId(); + recorder.recordNextSpanId(nextId.getSpanId()); + recorder.recordServiceType(OK_HTTP_CLIENT); + + InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); + if (invocation != null) { + invocation.getOrCreateAttachment(new AttachmentFactory() { + @Override + public Object createAttachment() { + return nextId; + } + }); + } + } catch (Throwable t) { + logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); + } + } + + private boolean validate(Object target) { + if (!(target instanceof UserRequestGetter)) { + logger.debug("Invalid target object. Need field accessor({}).", FIELD_USER_REQUEST); + return false; + } + + if (!(target instanceof UserResponseGetter)) { + logger.debug("Invalid target object. Need field accessor({}).", FIELD_USER_RESPONSE); + return false; + } + + if (!(target instanceof ConnectionGetter)) { + logger.debug("Invalid target object. Need field accessor({}).", FIELD_CONNECTION); + return false; + } + + return true; + } + + private String getHost(HttpUrl url) { + return url.port() != HttpUrl.defaultPort(url.scheme()) + ? url.host() + ":" + url.port() + : url.host(); + } + + @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; + } + + if (!validate(target)) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + + Request request = ((UserRequestGetter) target)._$PINPOINT$_getUserRequest(); + if (request != null) { + recorder.recordAttribute(AnnotationKey.HTTP_URL, request.httpUrl().toString()); + recorder.recordDestinationId(request.httpUrl().host() + ":" + request.httpUrl().port()); + } + + // clear attachment. + InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); + if(invocation != null && invocation.getAttachment() != null) { + invocation.removeAttachment(); + } + } finally { + trace.traceBlockEnd(); + } + } +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/RequestBuilderBuildMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/RequestBuilderBuildMethodInterceptor.java new file mode 100644 index 000000000000..1dcd698b2b2c --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/interceptor/RequestBuilderBuildMethodInterceptor.java @@ -0,0 +1,105 @@ +/* + * 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.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.*; +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.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.okhttp.*; +import com.squareup.okhttp.HttpUrl; +import com.squareup.okhttp.Request; + +/** + * @author jaehong.kim + */ +@Group(value = OkHttpConstants.SEND_REQUEST_SCOPE) +public class RequestBuilderBuildMethodInterceptor implements SimpleAroundInterceptor, OkHttpConstants { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor methodDescriptor; + private InterceptorGroup interceptorGroup; + + public RequestBuilderBuildMethodInterceptor(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.currentRawTraceObject(); + if (trace == null) { + return; + } + + try { + final Request.Builder builder = ((Request.Builder) target); + if (!trace.canSampled()) { + if (isDebug) { + logger.debug("set Sampling flag=false"); + } + ((Request.Builder) target).header(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); + return; + } + + final InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); + if (invocation == null || invocation.getAttachment() == null || !(invocation.getAttachment() instanceof TraceId)) { + logger.debug("Invalid interceptor group invocation. {}", invocation); + return; + } + + final TraceId nextId = (TraceId) invocation.getAttachment(); + builder.header(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); + builder.header(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); + + builder.header(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); + + builder.header(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); + builder.header(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); + builder.header(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); + + if (target instanceof HttpUrlGetter) { + final HttpUrl url = ((HttpUrlGetter) target)._$PINPOINT$_getHttpUrl(); + if (url != null) { + builder.header(Header.HTTP_HOST.toString(), url.host()); + } + } + } 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); + } + } +} \ No newline at end of file