Skip to content

Commit

Permalink
Add HttpSenderProvider SPI (#5533)
Browse files Browse the repository at this point in the history
  • Loading branch information
jack-berg committed Jun 16, 2023
1 parent c42f3df commit 8f1a7b1
Show file tree
Hide file tree
Showing 15 changed files with 201 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Comparing source compatibility of against
No changes.
2 changes: 1 addition & 1 deletion exporters/common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ dependencies {

annotationProcessor("com.google.auto.value:auto-value")

// We include helpers shared by gRPC or okhttp exporters but do not want to impose these
// We include helpers shared by gRPC exporters but do not want to impose these
// dependency on all of our consumers.
compileOnly("com.fasterxml.jackson.core:jackson-core")
compileOnly("com.squareup.okhttp3:okhttp")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@
import io.opentelemetry.exporter.internal.TlsConfigHelper;
import io.opentelemetry.exporter.internal.auth.Authenticator;
import io.opentelemetry.exporter.internal.marshal.Marshaler;
import io.opentelemetry.exporter.internal.okhttp.OkHttpHttpSender;
import io.opentelemetry.exporter.internal.retry.RetryPolicy;
import java.net.URI;
import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
Expand All @@ -34,6 +36,8 @@
public final class HttpExporterBuilder<T extends Marshaler> {
public static final long DEFAULT_TIMEOUT_SECS = 10;

private static final Logger LOGGER = Logger.getLogger(HttpExporterBuilder.class.getName());

private final String exporterName;
private final String type;

Expand Down Expand Up @@ -125,17 +129,28 @@ public HttpExporter<T> build() {
Map<String, String> headers = this.headers == null ? Collections.emptyMap() : this.headers;
Supplier<Map<String, String>> headerSupplier = () -> headers;

HttpSender httpSender =
new OkHttpHttpSender(
endpoint,
compressionEnabled,
exportAsJson ? "application/json" : "application/x-protobuf",
timeoutNanos,
headerSupplier,
authenticator,
retryPolicy,
tlsConfigHelper.getSslContext(),
tlsConfigHelper.getTrustManager());
HttpSender httpSender = null;
// TODO: once we publish multiple HttpSenderProviders, log warning when multiple are found
for (HttpSenderProvider httpSenderProvider :
ServiceLoader.load(HttpSenderProvider.class, HttpExporterBuilder.class.getClassLoader())) {
httpSender =
httpSenderProvider.createSender(
endpoint,
compressionEnabled,
exportAsJson ? "application/json" : "application/x-protobuf",
timeoutNanos,
headerSupplier,
authenticator,
retryPolicy,
tlsConfigHelper.getSslContext(),
tlsConfigHelper.getTrustManager());
LOGGER.log(Level.FINE, "Using HttpSender: " + httpSender.getClass().getName());
break;
}
if (httpSender == null) {
throw new IllegalStateException(
"No HttpSenderProvider found on classpath. Please add dependency on opentelemetry-exporter-http-sender-okhttp");
}

return new HttpExporter<>(exporterName, type, httpSender, meterProviderSupplier, exportAsJson);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.internal.http;

import io.opentelemetry.exporter.internal.auth.Authenticator;
import io.opentelemetry.exporter.internal.retry.RetryPolicy;
import java.util.Map;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;

/**
* A service provider interface (SPI) for providing {@link HttpSender}s backed by different HTTP
* client libraries.
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
public interface HttpSenderProvider {

/** Returns a {@link HttpSender} configured with the provided parameters. */
HttpSender createSender(
String endpoint,
boolean compressionEnabled,
String contentType,
long timeoutNanos,
Supplier<Map<String, String>> headerSupplier,
@Nullable Authenticator authenticator,
@Nullable RetryPolicy retryPolicy,
@Nullable SSLContext sslContext,
@Nullable X509TrustManager trustManager);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.internal.http;

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

import org.junit.jupiter.api.Test;

class HttpExporterTest {

@Test
void build_NoHttpSenderProvider() {
assertThatThrownBy(() -> new HttpExporterBuilder<>("name", "type", "http://localhost").build())
.isInstanceOf(IllegalStateException.class)
.hasMessage(
"No HttpSenderProvider found on classpath. Please add dependency on opentelemetry-exporter-http-sender-okhttp");
}
}
10 changes: 10 additions & 0 deletions exporters/http-sender/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
subprojects {
// Workaround https://github.com/gradle/gradle/issues/847
group = "io.opentelemetry.exporter.httpsender"
val proj = this
plugins.withId("java") {
configure<BasePluginExtension> {
archivesName.set("opentelemetry-exporter-http-sender-${proj.name}")
}
}
}
18 changes: 18 additions & 0 deletions exporters/http-sender/okhttp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
plugins {
id("otel.java-conventions")
id("otel.publish-conventions")

id("otel.animalsniffer-conventions")
}

description = "OpenTelemetry OkHttp HttpSender"
otelJava.moduleName.set("io.opentelemetry.exporter.http.okhttp.internal")

dependencies {
implementation(project(":exporters:common"))
implementation(project(":sdk:common"))

implementation("com.squareup.okhttp3:okhttp")

testImplementation("com.linecorp.armeria:armeria-junit5")
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.internal.okhttp;
package io.opentelemetry.exporter.http.okhttp.internal;

import io.opentelemetry.exporter.internal.auth.Authenticator;
import io.opentelemetry.exporter.internal.http.HttpSender;
import io.opentelemetry.exporter.internal.okhttp.OkHttpUtil;
import io.opentelemetry.exporter.internal.retry.RetryInterceptor;
import io.opentelemetry.exporter.internal.retry.RetryPolicy;
import io.opentelemetry.exporter.internal.retry.RetryUtil;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.http.okhttp.internal;

import io.opentelemetry.exporter.internal.auth.Authenticator;
import io.opentelemetry.exporter.internal.http.HttpSender;
import io.opentelemetry.exporter.internal.http.HttpSenderProvider;
import io.opentelemetry.exporter.internal.retry.RetryPolicy;
import java.util.Map;
import java.util.function.Supplier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import org.jetbrains.annotations.Nullable;

/**
* {@link HttpSender} SPI implementation for {@link OkHttpHttpSender}.
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
public class OkHttpHttpSenderProvider implements HttpSenderProvider {

@Override
public HttpSender createSender(
String endpoint,
boolean compressionEnabled,
String contentType,
long timeoutNanos,
Supplier<Map<String, String>> headerSupplier,
@Nullable Authenticator authenticator,
@Nullable RetryPolicy retryPolicy,
@Nullable SSLContext sslContext,
@Nullable X509TrustManager trustManager) {
return new OkHttpHttpSender(
endpoint,
compressionEnabled,
contentType,
timeoutNanos,
headerSupplier,
authenticator,
retryPolicy,
sslContext,
trustManager);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

/** Utilities for HTTP exporters. */
@ParametersAreNonnullByDefault
package io.opentelemetry.exporter.http.okhttp.internal;

import javax.annotation.ParametersAreNonnullByDefault;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.opentelemetry.exporter.http.okhttp.internal.OkHttpHttpSenderProvider
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.internal.auth;
package io.opentelemetry.exporter.http.okhttp.internal;

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.internal.okhttp;
package io.opentelemetry.exporter.http.okhttp.internal;

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

Expand All @@ -25,7 +25,11 @@ void compressionDefault() {
.isInstanceOfSatisfying(
HttpExporter.class,
otlp ->
assertThat(otlp).extracting("httpSender.compressionEnabled").isEqualTo(false));
assertThat(otlp)
.extracting("httpSender")
.isInstanceOf(OkHttpHttpSender.class)
.extracting("compressionEnabled")
.isEqualTo(false));
} finally {
exporter.shutdown();
}
Expand All @@ -39,7 +43,11 @@ void compressionNone() {
.isInstanceOfSatisfying(
HttpExporter.class,
otlp ->
assertThat(otlp).extracting("httpSender.compressionEnabled").isEqualTo(false));
assertThat(otlp)
.extracting("httpSender")
.isInstanceOf(OkHttpHttpSender.class)
.extracting("compressionEnabled")
.isEqualTo(false));
} finally {
exporter.shutdown();
}
Expand All @@ -52,7 +60,12 @@ void compressionGzip() {
assertThat(exporter)
.isInstanceOfSatisfying(
HttpExporter.class,
otlp -> assertThat(otlp).extracting("httpSender.compressionEnabled").isEqualTo(true));
otlp ->
assertThat(otlp)
.extracting("httpSender")
.isInstanceOf(OkHttpHttpSender.class)
.extracting("compressionEnabled")
.isEqualTo(true));
} finally {
exporter.shutdown();
}
Expand All @@ -67,7 +80,11 @@ void compressionEnabledAndDisabled() {
.isInstanceOfSatisfying(
HttpExporter.class,
otlp ->
assertThat(otlp).extracting("httpSender.compressionEnabled").isEqualTo(false));
assertThat(otlp)
.extracting("httpSender")
.isInstanceOf(OkHttpHttpSender.class)
.extracting("compressionEnabled")
.isEqualTo(false));
} finally {
exporter.shutdown();
}
Expand Down
1 change: 1 addition & 0 deletions exporters/otlp/all/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies {
api(project(":sdk:logs"))

implementation(project(":exporters:otlp:common"))
implementation(project(":exporters:http-sender:okhttp"))
implementation(project(":sdk-extensions:autoconfigure-spi"))

implementation("com.squareup.okhttp3:okhttp")
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ include(":extensions:incubator")
include(":extensions:kotlin")
include(":extensions:trace-propagators")
include(":exporters:common")
include(":exporters:http-sender:okhttp")
include(":exporters:jaeger")
include(":exporters:jaeger-proto")
include(":exporters:jaeger-thrift")
Expand Down

0 comments on commit 8f1a7b1

Please sign in to comment.