Add HttpSenderProvider SPI (#5533)

This commit is contained in:
jack-berg 2023-06-16 16:41:59 -05:00 committed by GitHub
parent c42f3df806
commit 8f1a7b1c95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 201 additions and 20 deletions

View File

@ -0,0 +1,2 @@
Comparing source compatibility of against
No changes.

View File

@ -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")

View File

@ -11,15 +11,17 @@ import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
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;
@ -34,6 +36,8 @@ import javax.net.ssl.X509TrustManager;
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;
@ -125,17 +129,28 @@ public final class HttpExporterBuilder<T extends Marshaler> {
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);
}

View File

@ -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);
}

View File

@ -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");
}
}

View File

@ -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}")
}
}
}

View File

@ -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")
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -0,0 +1 @@
io.opentelemetry.exporter.http.okhttp.internal.OkHttpHttpSenderProvider

View File

@ -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;

View File

@ -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;
@ -25,7 +25,11 @@ class HttpExporterBuilderTest {
.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();
}
@ -39,7 +43,11 @@ class HttpExporterBuilderTest {
.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();
}
@ -52,7 +60,12 @@ class HttpExporterBuilderTest {
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();
}
@ -67,7 +80,11 @@ class HttpExporterBuilderTest {
.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();
}

View File

@ -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")

View File

@ -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")