All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.undefinedlabs.scope.rules.OkHttp3ClientScopeAgentRuleInterceptor Maven / Gradle / Ivy

Go to download

Scope is a APM for tests to give engineering teams unprecedented visibility into their CI process to quickly identify, troubleshoot and fix failed builds. This artifact contains the classes to instrument OkHttp3 library.

There is a newer version: 0.15.1-beta.2
Show newest version
package com.undefinedlabs.scope.rules;

import com.undefinedlabs.scope.ScopeGlobalTracer;
import com.undefinedlabs.scope.events.EventFieldsFactory;
import com.undefinedlabs.scope.events.exception.ThrowableEvent;
import com.undefinedlabs.scope.rules.headers.OkHttp3HeadersAdapter;
import com.undefinedlabs.scope.rules.http.HttpHeadersExtractorForSpan;
import com.undefinedlabs.scope.rules.propagation.carriers.RequestBuilderInjectAdapter;
import com.undefinedlabs.scope.sender.internal.HttpSender;
import com.undefinedlabs.scope.settings.ScopeSettings;
import com.undefinedlabs.scope.settings.ScopeSettingsResolver;
import com.undefinedlabs.scope.utils.ScopeIOUtils;
import com.undefinedlabs.scope.utils.SpanUtils;
import com.undefinedlabs.scope.utils.StacktraceUtils;
import com.undefinedlabs.scope.utils.StringUtils;
import com.undefinedlabs.scope.utils.event.EventValues;
import com.undefinedlabs.scope.utils.sourcecode.ExceptionSourceCodeFactory;
import com.undefinedlabs.scope.utils.sourcecode.ExceptionSourceCodeFrame;
import com.undefinedlabs.scope.utils.tag.TagKeys;
import com.undefinedlabs.scope.utils.tag.TagValues;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import okio.Buffer;

public class OkHttp3ClientScopeAgentRuleInterceptor {

  public static final Interceptor SCOPE_OKHTTP_INTERCEPTOR =
      new Interceptor() {

        @Override
        public Response intercept(final Chain chain) throws IOException {
          if (HttpSender.SCOPE_JAVA_USER_AGENT.equals(chain.request().header("User-Agent"))) {
            return chain.proceed(chain.request());
          }

          final Tracer tracer = ScopeGlobalTracer.get();
          final Request request = chain.request();
          final Span previousActiveSpan = tracer.activeSpan();

          // If there is no previousActiveSpan, it is not created Span Client.
          if (previousActiveSpan == null) {
            return chain.proceed(request);
          }

          final String operationName = String.format("HTTP %s", request.method());
          final Span span =
              tracer
                  .buildSpan(operationName)
                  .withTag(TagKeys.COMPONENT, TagValues.Component.HTTP)
                  .withTag(TagKeys.SPAN_KIND, TagValues.Network.SPAN_KIND_CLIENT)
                  .withTag(TagKeys.Network.HTTP_URL, request.url().toString())
                  .withTag(TagKeys.Network.HTTP_METHOD, request.method())
                  .withTag(TagKeys.Network.PEER_HOSTNAME, request.url().host())
                  .withTag(TagKeys.Network.PEER_PORT, request.url().port())
                  .withTag(TagKeys.Network.PEER_SERVICE, TagValues.Network.Service.HTTP)
                  .start();

          SpanUtils.INSTANCE.setTagObject(
              span,
              TagKeys.Network.HTTP_REQUEST_HEADERS,
              HttpHeadersExtractorForSpan.DEFAULT.extract(
                  new OkHttp3HeadersAdapter(request.headers())));

          if ((boolean)
              ScopeSettingsResolver.INSTANCE
                  .get()
                  .getSetting(ScopeSettings.SCOPE_INSTRUMENTATION_HTTP_STACKTRACE)) {
            SpanUtils.INSTANCE.setTagObject(
                span,
                TagKeys.Stacktrace.STACKTRACE,
                StacktraceUtils.INSTANCE.createStackTraceFields(
                    Thread.currentThread().getStackTrace()));
          }

          if ((boolean)
              ScopeSettingsResolver.INSTANCE
                  .get()
                  .getSetting(ScopeSettings.SCOPE_INSTRUMENTATION_HTTP_PAYLOADS)) {
            if ("GET".equalsIgnoreCase(request.method())) {
              span.setTag(TagKeys.Network.HTTP_REQUEST_PAYLOAD, "");
            } else {
              if (request.body() != null) {
                final Buffer buffer = new Buffer();
                request.body().writeTo(buffer);
                span.setTag(
                    TagKeys.Network.HTTP_REQUEST_PAYLOAD,
                    ScopeIOUtils.getSubstring(buffer.inputStream()));
              } else {
                span.setTag(TagKeys.Network.HTTP_REQUEST_PAYLOAD, "");
              }
            }
          } else {
            span.setTag(
                TagKeys.Network.HTTP_REQUEST_PAYLOAD_UNAVAILABLE,
                TagValues.Network.HTTP_PAYLOAD_DISABLED);
          }

          final Request.Builder requestBuilder = chain.request().newBuilder();

          final Scope scope = tracer.activateSpan(span);
          tracer.inject(
              span.context(),
              Format.Builtin.HTTP_HEADERS,
              new RequestBuilderInjectAdapter(requestBuilder));

          try {
            final Request newRequest = requestBuilder.build();
            final Response response = chain.proceed(newRequest);

            if ((boolean)
                ScopeSettingsResolver.INSTANCE
                    .get()
                    .getSetting(ScopeSettings.SCOPE_INSTRUMENTATION_HTTP_PAYLOADS)) {
              if (response.body() != null) {
                if (response.body().byteStream() != null
                    && response.body().byteStream().markSupported()) {
                  final String responseStr =
                      ScopeIOUtils.getSubstring(response.body().byteStream());
                  span.setTag(
                      TagKeys.Network.HTTP_RESPONSE_PAYLOAD,
                      (StringUtils.isNotEmpty(responseStr) ? responseStr : null));
                  span.setTag(
                      TagKeys.Network.HTTP_RESPONSE_PAYLOAD_UNAVAILABLE,
                      (StringUtils.isNotEmpty(responseStr)
                          ? null
                          : TagValues.Network.HTTP_PAYLOAD_NOT_ACCESSIBLE));
                } else {
                  span.setTag(
                      TagKeys.Network.HTTP_RESPONSE_PAYLOAD_UNAVAILABLE,
                      TagValues.Network.HTTP_PAYLOAD_NOT_ACCESSIBLE);
                }
              } else {
                span.setTag(TagKeys.Network.HTTP_RESPONSE_PAYLOAD, "");
              }
            } else {
              span.setTag(
                  TagKeys.Network.HTTP_RESPONSE_PAYLOAD_UNAVAILABLE,
                  TagValues.Network.HTTP_PAYLOAD_DISABLED);
            }

            SpanUtils.INSTANCE.setTagObject(
                span,
                TagKeys.Network.HTTP_RESPONSE_HEADERS,
                HttpHeadersExtractorForSpan.DEFAULT.extract(
                    new OkHttp3HeadersAdapter(response.headers())));

            span.setTag(TagKeys.Network.HTTP_STATUS_CODE, response.code());
            return response;
          } catch (final Throwable throwable) {
            span.setTag(TagKeys.ERROR, true);

            final ExceptionSourceCodeFrame exceptionSourceCodeFrame =
                ExceptionSourceCodeFactory.INSTANCE.createFrame(throwable);
            final ThrowableEvent.Builder throwableEventBuilder = ThrowableEvent.newBuilder();
            throwableEventBuilder
                .withEventType(EventValues.General.ERROR)
                .withThrowable(exceptionSourceCodeFrame.getUserThrowable())
                .withSource(
                    exceptionSourceCodeFrame.getSourceCodeFrame().getLinkPathWithMethodLine());

            span.log(EventFieldsFactory.INSTANCE.createFields(throwableEventBuilder.build()));
            throw throwable;
          } finally {
            span.finish();
            scope.close();
          }
        }
      };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy