Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OkHttp migration to instrumentaion API #505

Merged
merged 16 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ android {

val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
dependencies {
androidTestImplementation(libs.findLibrary("androidx-test-core").get())
androidTestImplementation(libs.findLibrary("androidx-test-rules").get())
androidTestImplementation(libs.findLibrary("androidx-test-runner").get())
androidTestImplementation(libs.findLibrary("opentelemetry-sdk-testing").get())
coreLibraryDesugaring(libs.findLibrary("desugarJdkLibs").get())
Expand Down
11 changes: 6 additions & 5 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ androidx-lifecycle-process = "androidx.lifecycle:lifecycle-process:2.8.4"
findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2"
byteBuddy = { module = "net.bytebuddy:byte-buddy", version.ref = "byteBuddy" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
opentelemetry-instrumentation-api = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api"}
opentelemetry-instrumentation-apiSemconv = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator", version.ref = "opentelemetry-instrumentation-alpha"}
opentelemetry-instrumentation-api = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api" }
opentelemetry-instrumentation-apiSemconv = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator", version.ref = "opentelemetry-instrumentation-alpha" }
opentelemetry-instrumentation-okhttp = { module = "io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0", version.ref = "opentelemetry-instrumentation-alpha" }
opentelemetry-semconv = { module = "io.opentelemetry.semconv:opentelemetry-semconv", version.ref = "opentelemetry-semconv" }
opentelemetry-semconv-incubating = { module = "io.opentelemetry.semconv:opentelemetry-semconv-incubating", version.ref = "opentelemetry-semconv" }
opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api"}
opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api" }
opentelemetry-api-incubator = { module = "io.opentelemetry:opentelemetry-api-incubator" }
opentelemetry-sdk-extension-incubator = { module = "io.opentelemetry:opentelemetry-sdk-extension-incubator", version.ref = "opentelemetry-alpha" }
opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk"}
opentelemetry-context = { module = "io.opentelemetry:opentelemetry-context", version.ref = "opentelemetry"}
opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk" }
opentelemetry-context = { module = "io.opentelemetry:opentelemetry-context", version.ref = "opentelemetry" }
opentelemetry-exporter-logging = { module = "io.opentelemetry:opentelemetry-exporter-logging" }
opentelemetry-diskBuffering = { module = "io.opentelemetry.contrib:opentelemetry-disk-buffering", version.ref = "opentelemetry-contrib" }
opentelemetry-exporter-otlp = { module = "io.opentelemetry:opentelemetry-exporter-otlp", version.ref = "opentelemetry" }
Expand All @@ -43,6 +43,7 @@ auto-service-processor = { module = "com.google.auto.service:auto-service", vers
#Test tools
opentelemetry-sdk-testing = { module = "io.opentelemetry:opentelemetry-sdk-testing", version.ref = "opentelemetry" }
androidx-test-core = "androidx.test:core:1.6.1"
androidx-test-rules = "androidx.test:rules:1.6.1"
androidx-test-runner = "androidx.test:runner:1.6.1"
androidx-junit = "androidx.test.ext:junit:1.2.1"
mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" }
Expand Down
15 changes: 14 additions & 1 deletion instrumentation/okhttp/okhttp-3.0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,17 @@ automatically.
### Configuration

You can configure the automatic instrumentation by using the setters
in [OkHttpInstrumentationConfig](library/src/main/java/io/opentelemetry/instrumentation/library/okhttp/v3_0/OkHttpInstrumentationConfig.java)).
from
the [OkHttpInstrumentation](library/src/main/java/io/opentelemetry/instrumentation/library/okhttp/v3_0/OkHttpInstrumentation.java))
instance provided via the AndroidInstrumentationLoader as shown below:

```java
OkHttpInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(OkHttpInstrumentation.class);

// Call `instrumentation` setters.
```

> [!NOTE]
> You must make sure to apply any configurations **before** initializing your OpenTelemetryRum
> instance (i.e. calling OpenTelemetryRum.builder()...build()). Otherwise your configs won't be
> taken into account during the RUM initialization process.
Comment on lines +43 to +56
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like these docs and am wondering how we might document this more broadly in the near future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I've created this issue for it: #532

Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ android {
dependencies {
compileOnly(libs.okhttp)
api(libs.opentelemetry.instrumentation.okhttp)
api(project(":core"))
implementation(libs.opentelemetry.instrumentation.apiSemconv)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,29 @@

package io.opentelemetry.instrumentation.library.okhttp.v3_0;

import android.app.Application;
import com.google.auto.service.AutoService;
import io.opentelemetry.android.OpenTelemetryRum;
import io.opentelemetry.android.instrumentation.AndroidInstrumentation;
import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceResolver;
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
import io.opentelemetry.instrumentation.library.okhttp.v3_0.internal.OkHttp3Singletons;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jetbrains.annotations.NotNull;

/** Configuration for automatic instrumentation of okhttp requests. */
public final class OkHttpInstrumentationConfig {
private static List<String> capturedRequestHeaders = new ArrayList<>();
private static List<String> capturedResponseHeaders = new ArrayList<>();
private static Set<String> knownMethods = HttpConstants.KNOWN_METHODS;
private static Map<String, String> peerServiceMapping = new HashMap<>();
private static boolean emitExperimentalHttpClientMetrics;

private OkHttpInstrumentationConfig() {}
/** Instrumentation for okhttp requests. */
@AutoService(AndroidInstrumentation.class)
public class OkHttpInstrumentation implements AndroidInstrumentation {
private List<String> capturedRequestHeaders = new ArrayList<>();
private List<String> capturedResponseHeaders = new ArrayList<>();
private Set<String> knownMethods = HttpConstants.KNOWN_METHODS;
private Map<String, String> peerServiceMapping = new HashMap<>();
private boolean emitExperimentalHttpClientMetrics;

/**
* Configures the HTTP request headers that will be captured as span attributes as described in
Expand All @@ -36,11 +41,11 @@ private OkHttpInstrumentationConfig() {}
*
* @param requestHeaders A list of HTTP header names.
*/
public static void setCapturedRequestHeaders(List<String> requestHeaders) {
OkHttpInstrumentationConfig.capturedRequestHeaders = new ArrayList<>(requestHeaders);
public void setCapturedRequestHeaders(List<String> requestHeaders) {
capturedRequestHeaders = new ArrayList<>(requestHeaders);
}

public static List<String> getCapturedRequestHeaders() {
public List<String> getCapturedRequestHeaders() {
return capturedRequestHeaders;
}

Expand All @@ -56,11 +61,11 @@ public static List<String> getCapturedRequestHeaders() {
*
* @param responseHeaders A list of HTTP header names.
*/
public static void setCapturedResponseHeaders(List<String> responseHeaders) {
OkHttpInstrumentationConfig.capturedResponseHeaders = new ArrayList<>(responseHeaders);
public void setCapturedResponseHeaders(List<String> responseHeaders) {
capturedResponseHeaders = new ArrayList<>(responseHeaders);
}

public static List<String> getCapturedResponseHeaders() {
public List<String> getCapturedResponseHeaders() {
return capturedResponseHeaders;
}

Expand All @@ -79,11 +84,11 @@ public static List<String> getCapturedResponseHeaders() {
*
* @param knownMethods A set of recognized HTTP request methods.
*/
public static void setKnownMethods(Set<String> knownMethods) {
OkHttpInstrumentationConfig.knownMethods = new HashSet<>(knownMethods);
public void setKnownMethods(Set<String> knownMethods) {
this.knownMethods = new HashSet<>(knownMethods);
}

public static Set<String> getKnownMethods() {
public Set<String> getKnownMethods() {
return knownMethods;
}

Expand All @@ -92,11 +97,11 @@ public static Set<String> getKnownMethods() {
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/span-general.md#general-remote-service-attributes">the
* specification</a>.
*/
public static void setPeerServiceMapping(Map<String, String> peerServiceMapping) {
OkHttpInstrumentationConfig.peerServiceMapping = new HashMap<>(peerServiceMapping);
public void setPeerServiceMapping(Map<String, String> peerServiceMapping) {
this.peerServiceMapping = new HashMap<>(peerServiceMapping);
}

public static PeerServiceResolver newPeerServiceResolver() {
public PeerServiceResolver newPeerServiceResolver() {
return PeerServiceResolver.create(peerServiceMapping);
}

Expand All @@ -109,13 +114,17 @@ public static PeerServiceResolver newPeerServiceResolver() {
* href="https://github.com/open-telemetry/semantic-conventions/blob/main/specification/metrics/semantic_conventions/http-metrics.md#metric-httpclientresponsesize">
* the response size</a>.
*/
public static void setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
OkHttpInstrumentationConfig.emitExperimentalHttpClientMetrics =
emitExperimentalHttpClientMetrics;
public void setEmitExperimentalHttpClientMetrics(boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
}

public static boolean emitExperimentalHttpClientMetrics() {
public boolean emitExperimentalHttpClientMetrics() {
return emitExperimentalHttpClientMetrics;
}

@Override
public void install(
@NotNull Application application, @NotNull OpenTelemetryRum openTelemetryRum) {
OkHttp3Singletons.configure(this, openTelemetryRum.getOpenTelemetry());
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@

package io.opentelemetry.instrumentation.library.okhttp.v3_0.internal;

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientRequestResendCount;
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.library.okhttp.v3_0.OkHttpInstrumentationConfig;
import io.opentelemetry.instrumentation.library.okhttp.v3_0.OkHttpInstrumentation;
import io.opentelemetry.instrumentation.okhttp.v3_0.internal.ConnectionErrorSpanInterceptor;
import io.opentelemetry.instrumentation.okhttp.v3_0.internal.OkHttpAttributesGetter;
import io.opentelemetry.instrumentation.okhttp.v3_0.internal.OkHttpClientInstrumenterBuilderFactory;
import io.opentelemetry.instrumentation.okhttp.v3_0.internal.TracingInterceptor;
import java.util.function.Supplier;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
Expand All @@ -27,37 +26,36 @@
* any time.
*/
public final class OkHttp3Singletons {
private static final Interceptor NOOP_INTERCEPTOR = (chain -> chain.proceed(chain.request()));
public static Interceptor CONNECTION_ERROR_INTERCEPTOR = NOOP_INTERCEPTOR;
public static Interceptor TRACING_INTERCEPTOR = NOOP_INTERCEPTOR;

private static final Supplier<Instrumenter<Request, Response>> INSTRUMENTER =
CachedSupplier.create(
() ->
OkHttpClientInstrumenterBuilderFactory.create(GlobalOpenTelemetry.get())
.setCapturedRequestHeaders(
OkHttpInstrumentationConfig.getCapturedRequestHeaders())
.setCapturedResponseHeaders(
OkHttpInstrumentationConfig
.getCapturedResponseHeaders())
.setKnownMethods(OkHttpInstrumentationConfig.getKnownMethods())
// TODO: Do we really need to set the known methods on the span
// name
// extractor as well?
.setSpanNameExtractor(
x ->
HttpSpanNameExtractor.builder(
OkHttpAttributesGetter.INSTANCE)
.setKnownMethods(
OkHttpInstrumentationConfig
.getKnownMethods())
.build())
.addAttributeExtractor(
PeerServiceAttributesExtractor.create(
OkHttpAttributesGetter.INSTANCE,
OkHttpInstrumentationConfig
.newPeerServiceResolver()))
.setEmitExperimentalHttpClientMetrics(
OkHttpInstrumentationConfig
.emitExperimentalHttpClientMetrics())
.build());
public static void configure(
OkHttpInstrumentation instrumentation, OpenTelemetry openTelemetry) {
Instrumenter<Request, Response> instrumenter =
OkHttpClientInstrumenterBuilderFactory.create(openTelemetry)
.setCapturedRequestHeaders(instrumentation.getCapturedRequestHeaders())
.setCapturedResponseHeaders(instrumentation.getCapturedResponseHeaders())
.setKnownMethods(instrumentation.getKnownMethods())
// TODO: Do we really need to set the known methods on the span
// name
// extractor as well?
.setSpanNameExtractor(
x ->
HttpSpanNameExtractor.builder(
OkHttpAttributesGetter.INSTANCE)
.setKnownMethods(instrumentation.getKnownMethods())
.build())
.addAttributeExtractor(
PeerServiceAttributesExtractor.create(
OkHttpAttributesGetter.INSTANCE,
instrumentation.newPeerServiceResolver()))
.setEmitExperimentalHttpClientMetrics(
instrumentation.emitExperimentalHttpClientMetrics())
.build();
CONNECTION_ERROR_INTERCEPTOR = new ConnectionErrorSpanInterceptor(instrumenter);
TRACING_INTERCEPTOR = new TracingInterceptor(instrumenter, openTelemetry.getPropagators());
}

public static final Interceptor CALLBACK_CONTEXT_INTERCEPTOR =
chain -> {
Expand All @@ -81,18 +79,5 @@ public final class OkHttp3Singletons {
}
};

public static final Interceptor CONNECTION_ERROR_INTERCEPTOR =
new LazyInterceptor<>(
CachedSupplier.create(
() -> new ConnectionErrorSpanInterceptor(INSTRUMENTER.get())));

public static final Interceptor TRACING_INTERCEPTOR =
new LazyInterceptor<>(
CachedSupplier.create(
() ->
new TracingInterceptor(
INSTRUMENTER.get(),
GlobalOpenTelemetry.getPropagators())));

private OkHttp3Singletons() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class OkHttpInstrumentationConfigTest {
class OkHttpInstrumentationTest {
private OkHttpInstrumentation instrumentation;

@BeforeEach
void setUp() {
instrumentation = new OkHttpInstrumentation();
}

@Test
void validateDefaultHttpMethods() {
assertThat(OkHttpInstrumentationConfig.getKnownMethods())
assertThat(instrumentation.getKnownMethods())
.containsExactlyInAnyOrder(
"CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT",
"TRACE");
Expand Down
Loading