diff --git a/exporters/otlp-http/logs/src/test/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogExporterTest.java b/exporters/otlp-http/logs/src/test/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogExporterTest.java index e66973bc47a..731d125ac1d 100644 --- a/exporters/otlp-http/logs/src/test/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogExporterTest.java +++ b/exporters/otlp-http/logs/src/test/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogExporterTest.java @@ -24,6 +24,8 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.logs.ResourceLogsMarshaler; import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpExporter; +import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpExporterBuilder; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest; import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse; import io.opentelemetry.proto.logs.v1.ResourceLogs; @@ -183,6 +185,16 @@ void invalidConfig() { "Unsupported compression method. Supported compression methods include: gzip, none."); } + @Test + void testBuilderDelegate() { + assertThatCode( + () -> + OkHttpExporterBuilder.getDelegateBuilder( + OtlpHttpLogExporterBuilder.class, OtlpHttpLogExporter.builder()) + .setRetryPolicy(RetryPolicy.getDefault())) + .doesNotThrowAnyException(); + } + @Test void testExportUncompressed() { server.enqueue(successResponse()); diff --git a/exporters/otlp-http/metrics/src/test/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterTest.java b/exporters/otlp-http/metrics/src/test/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterTest.java index 01e883ad4af..de2ecf4d4ff 100644 --- a/exporters/otlp-http/metrics/src/test/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterTest.java +++ b/exporters/otlp-http/metrics/src/test/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterTest.java @@ -24,6 +24,8 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.metrics.ResourceMetricsMarshaler; import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpExporter; +import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpExporterBuilder; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest; import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse; import io.opentelemetry.proto.metrics.v1.ResourceMetrics; @@ -188,6 +190,16 @@ void invalidConfig() { .hasMessage("preferredTemporality"); } + @Test + void testBuilderDelegate() { + assertThatCode( + () -> + OkHttpExporterBuilder.getDelegateBuilder( + OtlpHttpMetricExporterBuilder.class, OtlpHttpMetricExporter.builder()) + .setRetryPolicy(RetryPolicy.getDefault())) + .doesNotThrowAnyException(); + } + @Test void testExportUncompressed() { server.enqueue(successResponse()); diff --git a/exporters/otlp-http/trace/src/test/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterTest.java b/exporters/otlp-http/trace/src/test/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterTest.java index d116dc9b536..168bc8aed89 100644 --- a/exporters/otlp-http/trace/src/test/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterTest.java +++ b/exporters/otlp-http/trace/src/test/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterTest.java @@ -26,6 +26,8 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpExporter; +import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpExporterBuilder; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.traces.ResourceSpansMarshaler; import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest; import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse; @@ -171,6 +173,16 @@ void invalidConfig() { "Unsupported compression method. Supported compression methods include: gzip, none."); } + @Test + void testBuilderDelegate() { + assertThatCode( + () -> + OkHttpExporterBuilder.getDelegateBuilder( + OtlpHttpSpanExporterBuilder.class, OtlpHttpSpanExporter.builder()) + .setRetryPolicy(RetryPolicy.getDefault())) + .doesNotThrowAnyException(); + } + @Test void testExportUncompressed() { server.enqueue(successResponse()); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/DefaultGrpcExporterBuilder.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/DefaultGrpcExporterBuilder.java index 123b75b1039..623451f6861 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/DefaultGrpcExporterBuilder.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/DefaultGrpcExporterBuilder.java @@ -15,7 +15,7 @@ import io.grpc.stub.MetadataUtils; import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import java.lang.reflect.Field; import java.net.URI; import java.net.URISyntaxException; @@ -120,7 +120,7 @@ public DefaultGrpcExporterBuilder addHeader(String key, String value) { } @Override - public GrpcExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { + public GrpcExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { this.retryPolicy = retryPolicy; return this; } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/GrpcExporterBuilder.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/GrpcExporterBuilder.java index d2923fed87c..985a07edb6f 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/GrpcExporterBuilder.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/GrpcExporterBuilder.java @@ -8,7 +8,7 @@ import io.grpc.ManagedChannel; import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import java.time.Duration; import java.util.concurrent.TimeUnit; @@ -28,7 +28,7 @@ public interface GrpcExporterBuilder { GrpcExporterBuilder addHeader(String key, String value); - GrpcExporterBuilder addRetryPolicy(RetryPolicy retryPolicy); + GrpcExporterBuilder setRetryPolicy(RetryPolicy retryPolicy); GrpcExporterBuilder setMeterProvider(MeterProvider meterProvider); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/GrpcStatusUtil.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/GrpcStatusUtil.java index 1a5914ba99c..c5de47ed1d5 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/GrpcStatusUtil.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/GrpcStatusUtil.java @@ -7,8 +7,6 @@ import io.opentelemetry.exporter.otlp.internal.CodedInputStream; import java.io.IOException; -import java.util.HashSet; -import java.util.Set; /** * Utilities for working with gRPC status without requiring dependencies on gRPC. @@ -27,23 +25,6 @@ public final class GrpcStatusUtil { public static final String GRPC_STATUS_UNAVAILABLE = "14"; public static final String GRPC_STATUS_DATA_LOSS = "15"; - private static final Set RETRYABLE_STATUS_CODES = new HashSet<>(); - - static { - RETRYABLE_STATUS_CODES.add(GrpcStatusUtil.GRPC_STATUS_CANCELLED); - RETRYABLE_STATUS_CODES.add(GrpcStatusUtil.GRPC_STATUS_DEADLINE_EXCEEDED); - RETRYABLE_STATUS_CODES.add(GrpcStatusUtil.GRPC_STATUS_RESOURCE_EXHAUSTED); - RETRYABLE_STATUS_CODES.add(GrpcStatusUtil.GRPC_STATUS_ABORTED); - RETRYABLE_STATUS_CODES.add(GrpcStatusUtil.GRPC_STATUS_OUT_OF_RANGE); - RETRYABLE_STATUS_CODES.add(GrpcStatusUtil.GRPC_STATUS_UNAVAILABLE); - RETRYABLE_STATUS_CODES.add(GrpcStatusUtil.GRPC_STATUS_DATA_LOSS); - } - - /** Returns the retryable gRPC status codes. */ - public static Set retryableStatusCodes() { - return RETRYABLE_STATUS_CODES; - } - /** Parses the message out of a serialized gRPC Status. */ public static String getStatusMessage(byte[] serializedStatus) throws IOException { CodedInputStream input = CodedInputStream.newInstance(serializedStatus); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/ManagedChannelUtil.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/ManagedChannelUtil.java index aed730468c3..e6589b3a0af 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/ManagedChannelUtil.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/ManagedChannelUtil.java @@ -12,8 +12,9 @@ import io.grpc.ManagedChannelBuilder; import io.grpc.netty.GrpcSslContexts; import io.grpc.netty.NettyChannelBuilder; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.TlsUtil; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; +import io.opentelemetry.exporter.otlp.internal.retry.RetryUtil; import io.opentelemetry.sdk.common.CompletableResultCode; import java.util.Collections; import java.util.HashMap; @@ -82,7 +83,7 @@ public static void setTrustedCertificatesPem( */ public static Map toServiceConfig(String serviceName, RetryPolicy retryPolicy) { List retryableStatusCodes = - GrpcStatusUtil.retryableStatusCodes().stream().map(Double::parseDouble).collect(toList()); + RetryUtil.retryableGrpcStatusCodes().stream().map(Double::parseDouble).collect(toList()); Map retryConfig = new HashMap<>(); retryConfig.put("retryableStatusCodes", retryableStatusCodes); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/OkHttpGrpcExporter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/OkHttpGrpcExporter.java index 3226dba6b4b..9a3892b9295 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/OkHttpGrpcExporter.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/OkHttpGrpcExporter.java @@ -28,6 +28,7 @@ import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.exporter.otlp.internal.Marshaler; +import io.opentelemetry.exporter.otlp.internal.retry.RetryUtil; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.internal.ThrottlingLogger; import java.io.IOException; @@ -235,7 +236,7 @@ static boolean isRetryable(Response response) { // We don't check trailers for retry since retryable error codes always come with response // headers, not trailers, in practice. String grpcStatus = response.header(GRPC_STATUS); - return GrpcStatusUtil.retryableStatusCodes().contains(grpcStatus); + return RetryUtil.retryableGrpcStatusCodes().contains(grpcStatus); } // From grpc-java diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/OkHttpGrpcExporterBuilder.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/OkHttpGrpcExporterBuilder.java index c1c7c0f4610..6a40ca7bf47 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/OkHttpGrpcExporterBuilder.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/grpc/OkHttpGrpcExporterBuilder.java @@ -8,10 +8,10 @@ import io.grpc.ManagedChannel; import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.TlsUtil; import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpUtil; -import io.opentelemetry.exporter.otlp.internal.okhttp.RetryInterceptor; +import io.opentelemetry.exporter.otlp.internal.retry.RetryInterceptor; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; @@ -109,7 +109,7 @@ public OkHttpGrpcExporterBuilder addHeader(String key, String value) { } @Override - public GrpcExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { + public GrpcExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { this.retryPolicy = retryPolicy; return this; } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/OkHttpExporter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/OkHttpExporter.java index 586a24f9140..5dc1a70a867 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/OkHttpExporter.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/OkHttpExporter.java @@ -9,6 +9,7 @@ import io.opentelemetry.exporter.otlp.internal.ExporterMetrics; import io.opentelemetry.exporter.otlp.internal.Marshaler; import io.opentelemetry.exporter.otlp.internal.grpc.GrpcStatusUtil; +import io.opentelemetry.exporter.otlp.internal.retry.RetryUtil; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.internal.ThrottlingLogger; import java.io.IOException; @@ -131,6 +132,10 @@ public CompletableResultCode shutdown() { return result; } + static boolean isRetryable(Response response) { + return RetryUtil.retryableHttpResponseCodes().contains(response.code()); + } + private static RequestBody gzipRequestBody(RequestBody requestBody) { return new RequestBody() { @Override diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/OkHttpExporterBuilder.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/OkHttpExporterBuilder.java index bb6db3ebcd0..1985718916d 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/OkHttpExporterBuilder.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/OkHttpExporterBuilder.java @@ -8,6 +8,9 @@ import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.exporter.otlp.internal.Marshaler; import io.opentelemetry.exporter.otlp.internal.TlsUtil; +import io.opentelemetry.exporter.otlp.internal.retry.RetryInterceptor; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; +import java.lang.reflect.Field; import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; @@ -31,6 +34,7 @@ public final class OkHttpExporterBuilder { private boolean compressionEnabled = false; @Nullable private Headers.Builder headersBuilder; @Nullable private byte[] trustedCertificatesPem; + @Nullable private RetryPolicy retryPolicy; private MeterProvider meterProvider = MeterProvider.noop(); public OkHttpExporterBuilder(String type, String defaultEndpoint) { @@ -91,6 +95,11 @@ public OkHttpExporterBuilder setMeterProvider(MeterProvider meterProvider) { return this; } + public OkHttpExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + this.retryPolicy = retryPolicy; + return this; + } + public OkHttpExporter build() { OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() @@ -110,7 +119,32 @@ public OkHttpExporter build() { Headers headers = headersBuilder == null ? null : headersBuilder.build(); + if (retryPolicy != null) { + clientBuilder.addInterceptor(new RetryInterceptor(retryPolicy, OkHttpExporter::isRetryable)); + } + return new OkHttpExporter<>( type, clientBuilder.build(), meterProvider, endpoint, headers, compressionEnabled); } + + /** + * Reflectively access a {@link OkHttpExporterBuilder} instance in field called "delegate" of the + * instance. + * + * @throws IllegalArgumentException if the instance does not contain a field called "delegate" of + * type {@link OkHttpExporterBuilder} + */ + public static OkHttpExporterBuilder getDelegateBuilder(Class type, T instance) { + try { + Field field = type.getDeclaredField("delegate"); + field.setAccessible(true); + Object value = field.get(instance); + if (!(value instanceof OkHttpExporterBuilder)) { + throw new IllegalArgumentException("delegate field is not type OkHttpExporterBuilder"); + } + return (OkHttpExporterBuilder) value; + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IllegalArgumentException("Unable to access delegate reflectively.", e); + } + } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/RetryInterceptor.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryInterceptor.java similarity index 95% rename from exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/RetryInterceptor.java rename to exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryInterceptor.java index e9bcf0f60f7..de73a951e61 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/okhttp/RetryInterceptor.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryInterceptor.java @@ -3,9 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.exporter.otlp.internal.okhttp; +package io.opentelemetry.exporter.otlp.internal.retry; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import java.io.IOException; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/RetryPolicy.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryPolicy.java similarity index 96% rename from exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/RetryPolicy.java rename to exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryPolicy.java index cb7bfff1da8..d27c19823ce 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/RetryPolicy.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryPolicy.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.exporter.otlp.internal; +package io.opentelemetry.exporter.otlp.internal.retry; import com.google.auto.value.AutoValue; import java.time.Duration; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/RetryPolicyBuilder.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryPolicyBuilder.java similarity index 97% rename from exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/RetryPolicyBuilder.java rename to exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryPolicyBuilder.java index 01184f5899d..a1b29055100 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/RetryPolicyBuilder.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryPolicyBuilder.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.exporter.otlp.internal; +package io.opentelemetry.exporter.otlp.internal.retry; import static io.opentelemetry.api.internal.Utils.checkArgument; import static java.util.Objects.requireNonNull; diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryUtil.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryUtil.java new file mode 100644 index 00000000000..0e84652aa79 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/retry/RetryUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp.internal.retry; + +import io.opentelemetry.exporter.otlp.internal.grpc.GrpcStatusUtil; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public class RetryUtil { + + private static final Set RETRYABLE_GRPC_STATUS_CODES; + private static final Set RETRYABLE_HTTP_STATUS_CODES = + Collections.unmodifiableSet(new HashSet<>(Arrays.asList(429, 502, 503, 504))); + + static { + Set retryableGrpcStatusCodes = new HashSet<>(); + retryableGrpcStatusCodes.add(GrpcStatusUtil.GRPC_STATUS_CANCELLED); + retryableGrpcStatusCodes.add(GrpcStatusUtil.GRPC_STATUS_DEADLINE_EXCEEDED); + retryableGrpcStatusCodes.add(GrpcStatusUtil.GRPC_STATUS_RESOURCE_EXHAUSTED); + retryableGrpcStatusCodes.add(GrpcStatusUtil.GRPC_STATUS_ABORTED); + retryableGrpcStatusCodes.add(GrpcStatusUtil.GRPC_STATUS_OUT_OF_RANGE); + retryableGrpcStatusCodes.add(GrpcStatusUtil.GRPC_STATUS_UNAVAILABLE); + retryableGrpcStatusCodes.add(GrpcStatusUtil.GRPC_STATUS_DATA_LOSS); + RETRYABLE_GRPC_STATUS_CODES = Collections.unmodifiableSet(retryableGrpcStatusCodes); + } + + private RetryUtil() {} + + /** Returns the retryable gRPC status codes. */ + public static Set retryableGrpcStatusCodes() { + return RETRYABLE_GRPC_STATUS_CODES; + } + + /** Returns the retryable HTTP status codes. */ + public static Set retryableHttpResponseCodes() { + return RETRYABLE_HTTP_STATUS_CODES; + } +} diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/grpc/ManagedChannelUtilTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/grpc/ManagedChannelUtilTest.java index 3315f77f875..bd38e83058e 100644 --- a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/grpc/ManagedChannelUtilTest.java +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/grpc/ManagedChannelUtilTest.java @@ -9,7 +9,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.grpc.ManagedChannelBuilder; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import java.util.Map; import org.junit.jupiter.api.Test; import org.skyscreamer.jsonassert.JSONAssert; diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/okhttp/RetryInterceptorTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/retry/RetryInterceptorTest.java similarity index 97% rename from exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/okhttp/RetryInterceptorTest.java rename to exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/retry/RetryInterceptorTest.java index ab7078db5d9..8895097e71e 100644 --- a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/okhttp/RetryInterceptorTest.java +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/retry/RetryInterceptorTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.exporter.otlp.internal.okhttp; +package io.opentelemetry.exporter.otlp.internal.retry; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.doNothing; @@ -14,7 +14,6 @@ import com.linecorp.armeria.common.HttpResponse; import com.linecorp.armeria.common.HttpStatus; import com.linecorp.armeria.testing.junit5.server.mock.MockWebServerExtension; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import java.io.IOException; import java.time.Duration; import java.util.concurrent.TimeUnit; diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/RetryPolicyTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/retry/RetryPolicyTest.java similarity index 97% rename from exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/RetryPolicyTest.java rename to exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/retry/RetryPolicyTest.java index 785b9a866c1..3e3d2832200 100644 --- a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/RetryPolicyTest.java +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/retry/RetryPolicyTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.exporter.otlp.internal; +package io.opentelemetry.exporter.otlp.internal.retry; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/exporters/otlp/logs/build.gradle.kts b/exporters/otlp/logs/build.gradle.kts index 248e1191fe8..166a639bfac 100644 --- a/exporters/otlp/logs/build.gradle.kts +++ b/exporters/otlp/logs/build.gradle.kts @@ -10,7 +10,8 @@ otelJava.moduleName.set("io.opentelemetry.exporter.otlp.logs") dependencies { api(project(":sdk:logs")) - api(project(":exporters:otlp:common")) + + implementation(project(":exporters:otlp:common")) compileOnly("io.grpc:grpc-stub") diff --git a/exporters/otlp/logs/src/test/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogExporterTest.java b/exporters/otlp/logs/src/test/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogExporterTest.java index 663366706b2..c4329bcb41d 100644 --- a/exporters/otlp/logs/src/test/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogExporterTest.java +++ b/exporters/otlp/logs/src/test/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogExporterTest.java @@ -9,9 +9,9 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.OkHttpGrpcExporterBuilder; import io.opentelemetry.exporter.otlp.internal.logs.ResourceLogsMarshaler; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporterBuilder; @@ -80,8 +80,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certifica } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/logs/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyLogExporterTest.java b/exporters/otlp/logs/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyLogExporterTest.java index 0e46777e908..11f3bced66a 100644 --- a/exporters/otlp/logs/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyLogExporterTest.java +++ b/exporters/otlp/logs/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyLogExporterTest.java @@ -10,9 +10,9 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; import io.opentelemetry.exporter.otlp.internal.logs.ResourceLogsMarshaler; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporterBuilder; @@ -41,7 +41,7 @@ void testBuilderDelegate() { () -> DefaultGrpcExporterBuilder.getDelegateBuilder( OtlpGrpcLogExporterBuilder.class, OtlpGrpcLogExporter.builder()) - .addRetryPolicy(RetryPolicy.getDefault())) + .setRetryPolicy(RetryPolicy.getDefault())) .doesNotThrowAnyException(); } @@ -92,8 +92,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certifica } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/logs/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyShadedLogExporterTest.java b/exporters/otlp/logs/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyShadedLogExporterTest.java index c96bc5dbbf9..0f61a61a02f 100644 --- a/exporters/otlp/logs/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyShadedLogExporterTest.java +++ b/exporters/otlp/logs/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyShadedLogExporterTest.java @@ -9,9 +9,9 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; import io.opentelemetry.exporter.otlp.internal.logs.ResourceLogsMarshaler; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporterBuilder; @@ -81,8 +81,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certifica } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/logs/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyOkHttpLogExporterTest.java b/exporters/otlp/logs/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyOkHttpLogExporterTest.java index cdcff23bd7b..a42278d53e1 100644 --- a/exporters/otlp/logs/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyOkHttpLogExporterTest.java +++ b/exporters/otlp/logs/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcNettyOkHttpLogExporterTest.java @@ -9,9 +9,9 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; import io.opentelemetry.exporter.otlp.internal.logs.ResourceLogsMarshaler; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporterBuilder; @@ -81,8 +81,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certifica } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/metrics/build.gradle.kts b/exporters/otlp/metrics/build.gradle.kts index da394f1184e..76c4ce872ff 100644 --- a/exporters/otlp/metrics/build.gradle.kts +++ b/exporters/otlp/metrics/build.gradle.kts @@ -10,7 +10,8 @@ otelJava.moduleName.set("io.opentelemetry.exporter.otlp.metrics") dependencies { api(project(":sdk:metrics")) - api(project(":exporters:otlp:common")) + + implementation(project(":exporters:otlp:common")) compileOnly("io.grpc:grpc-stub") diff --git a/exporters/otlp/metrics/src/test/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterTest.java b/exporters/otlp/metrics/src/test/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterTest.java index 8cf5ecffa1e..14578c265d9 100644 --- a/exporters/otlp/metrics/src/test/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterTest.java +++ b/exporters/otlp/metrics/src/test/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterTest.java @@ -10,9 +10,9 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.OkHttpGrpcExporterBuilder; import io.opentelemetry.exporter.otlp.internal.metrics.ResourceMetricsMarshaler; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporterBuilder; @@ -83,8 +83,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certif } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/metrics/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcNettyMetricExporterTest.java b/exporters/otlp/metrics/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcNettyMetricExporterTest.java index 5b777e5abd5..4006f8ba521 100644 --- a/exporters/otlp/metrics/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcNettyMetricExporterTest.java +++ b/exporters/otlp/metrics/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcNettyMetricExporterTest.java @@ -11,9 +11,9 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; import io.opentelemetry.exporter.otlp.internal.metrics.ResourceMetricsMarshaler; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporterBuilder; @@ -43,7 +43,7 @@ void testBuilderDelegate() { () -> DefaultGrpcExporterBuilder.getDelegateBuilder( OtlpGrpcMetricExporterBuilder.class, OtlpGrpcMetricExporter.builder()) - .addRetryPolicy(RetryPolicy.getDefault())) + .setRetryPolicy(RetryPolicy.getDefault())) .doesNotThrowAnyException(); } @@ -94,8 +94,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certif } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/metrics/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcNettyShadedMetricExporterTest.java b/exporters/otlp/metrics/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcNettyShadedMetricExporterTest.java index d597213b0a1..2353f1e1eb5 100644 --- a/exporters/otlp/metrics/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcNettyShadedMetricExporterTest.java +++ b/exporters/otlp/metrics/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcNettyShadedMetricExporterTest.java @@ -10,9 +10,9 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; import io.opentelemetry.exporter.otlp.internal.metrics.ResourceMetricsMarshaler; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporterBuilder; @@ -83,8 +83,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certif } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/metrics/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcOkHttpMetricExporterTest.java b/exporters/otlp/metrics/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcOkHttpMetricExporterTest.java index 493c5c82ebf..b6f183e547b 100644 --- a/exporters/otlp/metrics/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcOkHttpMetricExporterTest.java +++ b/exporters/otlp/metrics/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcOkHttpMetricExporterTest.java @@ -10,9 +10,9 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; import io.opentelemetry.exporter.otlp.internal.metrics.ResourceMetricsMarshaler; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporterBuilder; @@ -83,8 +83,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certif } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractGrpcTelemetryExporterTest.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractGrpcTelemetryExporterTest.java index 5320bfdafec..30b25d1ced2 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractGrpcTelemetryExporterTest.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractGrpcTelemetryExporterTest.java @@ -20,9 +20,9 @@ import com.linecorp.armeria.testing.junit5.server.ServerExtension; import io.github.netmikey.logunit.api.LogCapturer; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporter; import io.opentelemetry.exporter.otlp.internal.grpc.OkHttpGrpcExporter; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest; import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse; import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest; @@ -533,7 +533,7 @@ private List toProto(List telemetry) { private TelemetryExporter retryingExporter() { return exporterBuilder() .setEndpoint(server.httpUri().toString()) - .addRetryPolicy( + .setRetryPolicy( RetryPolicy.builder() .setMaxAttempts(2) // We don't validate backoff time itself in these tests, just that retries diff --git a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/TelemetryExporterBuilder.java b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/TelemetryExporterBuilder.java index ea9f1c4aadc..3748cd63696 100644 --- a/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/TelemetryExporterBuilder.java +++ b/exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/TelemetryExporterBuilder.java @@ -5,7 +5,7 @@ package io.opentelemetry.exporter.otlp.testing.internal; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import java.time.Duration; import java.util.concurrent.TimeUnit; @@ -22,7 +22,7 @@ public interface TelemetryExporterBuilder { TelemetryExporterBuilder setTrustedCertificates(byte[] certificates); - TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy); + TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy); TelemetryExporter build(); } diff --git a/exporters/otlp/trace/build.gradle.kts b/exporters/otlp/trace/build.gradle.kts index d91dbc6eeec..aef634cafc8 100644 --- a/exporters/otlp/trace/build.gradle.kts +++ b/exporters/otlp/trace/build.gradle.kts @@ -11,7 +11,8 @@ otelJava.moduleName.set("io.opentelemetry.exporter.otlp.trace") dependencies { api(project(":sdk:trace")) - api(project(":exporters:otlp:common")) + + implementation(project(":exporters:otlp:common")) compileOnly("io.grpc:grpc-stub") diff --git a/exporters/otlp/trace/src/test/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporterTest.java b/exporters/otlp/trace/src/test/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporterTest.java index 31efa90a453..cba67bc3ed8 100644 --- a/exporters/otlp/trace/src/test/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporterTest.java +++ b/exporters/otlp/trace/src/test/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporterTest.java @@ -12,8 +12,8 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.OkHttpGrpcExporterBuilder; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.traces.ResourceSpansMarshaler; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; @@ -85,8 +85,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certific } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/trace/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcNettySpanExporterTest.java b/exporters/otlp/trace/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcNettySpanExporterTest.java index 2cf4d2954a5..f251d1aafd0 100644 --- a/exporters/otlp/trace/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcNettySpanExporterTest.java +++ b/exporters/otlp/trace/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcNettySpanExporterTest.java @@ -13,8 +13,8 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.traces.ResourceSpansMarshaler; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; @@ -46,7 +46,7 @@ void builderDelegate() { () -> DefaultGrpcExporterBuilder.getDelegateBuilder( OtlpGrpcSpanExporterBuilder.class, OtlpGrpcSpanExporter.builder()) - .addRetryPolicy(RetryPolicy.getDefault())) + .setRetryPolicy(RetryPolicy.getDefault())) .doesNotThrowAnyException(); } @@ -97,8 +97,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certific } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/trace/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcNettyShadedSpanExporterTest.java b/exporters/otlp/trace/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcNettyShadedSpanExporterTest.java index 43c22be6bfc..761d9b624cb 100644 --- a/exporters/otlp/trace/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcNettyShadedSpanExporterTest.java +++ b/exporters/otlp/trace/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcNettyShadedSpanExporterTest.java @@ -12,8 +12,8 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.traces.ResourceSpansMarshaler; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; @@ -86,8 +86,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certific } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/exporters/otlp/trace/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcOkHttpSpanExporterTest.java b/exporters/otlp/trace/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcOkHttpSpanExporterTest.java index a68f6847e8c..6fa0e4f20b4 100644 --- a/exporters/otlp/trace/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcOkHttpSpanExporterTest.java +++ b/exporters/otlp/trace/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcOkHttpSpanExporterTest.java @@ -12,8 +12,8 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.exporter.otlp.internal.Marshaler; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.exporter.otlp.internal.traces.ResourceSpansMarshaler; import io.opentelemetry.exporter.otlp.testing.internal.AbstractGrpcTelemetryExporterTest; import io.opentelemetry.exporter.otlp.testing.internal.TelemetryExporter; @@ -86,8 +86,8 @@ public TelemetryExporterBuilder setTrustedCertificates(byte[] certific } @Override - public TelemetryExporterBuilder addRetryPolicy(RetryPolicy retryPolicy) { - builder.delegate.addRetryPolicy(retryPolicy); + public TelemetryExporterBuilder setRetryPolicy(RetryPolicy retryPolicy) { + builder.delegate.setRetryPolicy(retryPolicy); return this; } diff --git a/sdk-extensions/autoconfigure/build.gradle.kts b/sdk-extensions/autoconfigure/build.gradle.kts index a8bb4985fe7..ffd8832b406 100644 --- a/sdk-extensions/autoconfigure/build.gradle.kts +++ b/sdk-extensions/autoconfigure/build.gradle.kts @@ -17,6 +17,7 @@ dependencies { compileOnly(project(":exporters:logging")) compileOnly(project(":exporters:otlp:all")) compileOnly(project(":exporters:otlp:metrics")) + compileOnly(project(":exporters:otlp:common")) compileOnly(project(":exporters:otlp-http:trace")) compileOnly(project(":exporters:otlp-http:metrics")) compileOnly(project(":exporters:prometheus")) @@ -57,6 +58,7 @@ testing { implementation(project(":exporters:logging")) implementation(project(":exporters:otlp:all")) implementation(project(":exporters:otlp:metrics")) + implementation(project(":exporters:otlp:common")) implementation(project(":exporters:prometheus")) implementation(project(":exporters:zipkin")) implementation(project(":sdk-extensions:resources")) @@ -119,6 +121,7 @@ testing { dependencies { implementation(project(":exporters:otlp:all")) implementation(project(":exporters:otlp:metrics")) + implementation(project(":exporters:otlp:common")) implementation(project(":sdk:testing")) implementation("io.opentelemetry.proto:opentelemetry-proto") @@ -139,6 +142,7 @@ testing { dependencies { implementation(project(":exporters:otlp-http:trace")) implementation(project(":exporters:otlp-http:metrics")) + implementation(project(":exporters:otlp:common")) implementation(project(":sdk:testing")) implementation("com.google.guava:guava") diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MetricExporterConfiguration.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MetricExporterConfiguration.java index f8ae1c4fbea..7512b562d2a 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MetricExporterConfiguration.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MetricExporterConfiguration.java @@ -13,6 +13,7 @@ import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; +import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpExporterBuilder; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder; import io.opentelemetry.exporter.prometheus.PrometheusHttpServer; @@ -105,7 +106,9 @@ static MetricExporter configureOtlpMetrics( builder::setCompression, builder::setTimeout, builder::setTrustedCertificates, - (unused) -> {}); + retryPolicy -> + OkHttpExporterBuilder.getDelegateBuilder(OtlpHttpMetricExporterBuilder.class, builder) + .setRetryPolicy(retryPolicy)); OtlpConfigUtil.configureOtlpAggregationTemporality(config, builder::setPreferredTemporality); exporter = builder.build(); @@ -134,7 +137,7 @@ static MetricExporter configureOtlpMetrics( retryPolicy -> DefaultGrpcExporterBuilder.getDelegateBuilder( OtlpGrpcMetricExporterBuilder.class, builder) - .addRetryPolicy(retryPolicy)); + .setRetryPolicy(retryPolicy)); OtlpConfigUtil.configureOtlpAggregationTemporality(config, builder::setPreferredTemporality); exporter = builder.build(); diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtil.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtil.java index 05a7af743f5..85755beb7ff 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtil.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/OtlpConfigUtil.java @@ -5,7 +5,7 @@ package io.opentelemetry.sdk.autoconfigure; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfiguration.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfiguration.java index 16338739950..ef7a34ed0b4 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfiguration.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfiguration.java @@ -20,6 +20,7 @@ import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder; import io.opentelemetry.exporter.otlp.internal.grpc.DefaultGrpcExporterBuilder; +import io.opentelemetry.exporter.otlp.internal.okhttp.OkHttpExporterBuilder; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; @@ -144,7 +145,9 @@ static SpanExporter configureOtlp(ConfigProperties config, MeterProvider meterPr builder::setCompression, builder::setTimeout, builder::setTrustedCertificates, - unused -> {}); + retryPolicy -> + OkHttpExporterBuilder.getDelegateBuilder(OtlpHttpSpanExporterBuilder.class, builder) + .setRetryPolicy(retryPolicy)); builder.setMeterProvider(meterProvider); @@ -167,8 +170,7 @@ static SpanExporter configureOtlp(ConfigProperties config, MeterProvider meterPr retryPolicy -> DefaultGrpcExporterBuilder.getDelegateBuilder( OtlpGrpcSpanExporterBuilder.class, builder) - .addRetryPolicy(retryPolicy)); - + .setRetryPolicy(retryPolicy)); builder.setMeterProvider(meterProvider); return builder.build(); diff --git a/sdk-extensions/autoconfigure/src/testOtlpGrpc/java/io/opentelemetry/sdk/autoconfigure/OtlpGrpcRetryTest.java b/sdk-extensions/autoconfigure/src/testOtlpGrpc/java/io/opentelemetry/sdk/autoconfigure/OtlpGrpcRetryTest.java index 830141eb834..c472d0fabae 100644 --- a/sdk-extensions/autoconfigure/src/testOtlpGrpc/java/io/opentelemetry/sdk/autoconfigure/OtlpGrpcRetryTest.java +++ b/sdk-extensions/autoconfigure/src/testOtlpGrpc/java/io/opentelemetry/sdk/autoconfigure/OtlpGrpcRetryTest.java @@ -15,8 +15,8 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.exporter.otlp.internal.RetryPolicy; -import io.opentelemetry.exporter.otlp.internal.grpc.GrpcStatusUtil; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; +import io.opentelemetry.exporter.otlp.internal.retry.RetryUtil; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.metrics.SdkMeterProvider; @@ -129,7 +129,7 @@ private static void testRetryableStatusCodes( CompletableResultCode resultCode = exporter.apply(dataSupplier.get()).join(10, TimeUnit.SECONDS); boolean retryable = - GrpcStatusUtil.retryableStatusCodes().contains(String.valueOf(code.value())); + RetryUtil.retryableGrpcStatusCodes().contains(String.valueOf(code.value())); boolean expectedResult = retryable || code == Status.Code.OK; assertThat(resultCode.isSuccess()) .as( @@ -152,7 +152,7 @@ private static void testDefaultRetryPolicy( // Set the server to fail with a retryable status code for the max attempts int maxAttempts = RetryPolicy.getDefault().getMaxAttempts(); int retryableCode = - GrpcStatusUtil.retryableStatusCodes().stream().map(Integer::parseInt).findFirst().get(); + RetryUtil.retryableGrpcStatusCodes().stream().map(Integer::parseInt).findFirst().get(); for (int i = 0; i < maxAttempts; i++) { server.responseStatuses.add(Status.fromCodeValue(retryableCode)); } diff --git a/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpConfigTest.java b/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpConfigTest.java index 0fa82e545f9..ff0bd787849 100644 --- a/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpConfigTest.java +++ b/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpConfigTest.java @@ -13,19 +13,10 @@ import static org.awaitility.Awaitility.await; import com.google.common.collect.Lists; -import com.google.protobuf.Message; -import com.linecorp.armeria.common.HttpResponse; -import com.linecorp.armeria.common.HttpStatus; -import com.linecorp.armeria.common.RequestHeaders; -import com.linecorp.armeria.server.HttpService; -import com.linecorp.armeria.server.ServerBuilder; -import com.linecorp.armeria.testing.junit5.server.ServerExtension; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest; -import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; @@ -40,126 +31,26 @@ import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.data.StatusData; import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import okhttp3.OkHttpClient; -import okhttp3.tls.HeldCertificate; -import okio.Buffer; -import okio.GzipSource; -import okio.Okio; import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.BeforeAllCallback; -import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.RegisterExtension; class OtlpHttpConfigTest { - private static final BlockingQueue traceRequests = - new LinkedBlockingDeque<>(); - private static final BlockingQueue metricRequests = - new LinkedBlockingDeque<>(); - private static final BlockingQueue requestHeaders = new LinkedBlockingDeque<>(); - private static final String canonicalHostName; - - static { - try { - canonicalHostName = InetAddress.getByName("localhost").getCanonicalHostName(); - } catch (UnknownHostException e) { - throw new IllegalStateException("Error resolving canonical host name.", e); - } - } - - @RegisterExtension - @Order(1) - public static final CertificateExtension certificateExtension = new CertificateExtension(); - - private static class CertificateExtension implements BeforeAllCallback { - private HeldCertificate heldCertificate; - private String filePath; - - @Override - public void beforeAll(ExtensionContext context) throws Exception { - heldCertificate = - new HeldCertificate.Builder() - .commonName("localhost") - .addSubjectAlternativeName(canonicalHostName) - .build(); - Path file = Files.createTempFile("test-cert", ".pem"); - Files.write(file, heldCertificate.certificatePem().getBytes(StandardCharsets.UTF_8)); - filePath = file.toAbsolutePath().toString(); - } - } - @RegisterExtension - @Order(2) - public static final ServerExtension server = - new ServerExtension() { - @Override - protected void configure(ServerBuilder sb) { - sb.service( - "/v1/traces", - httpService(traceRequests, ExportTraceServiceRequest.getDefaultInstance())) - .service( - "/v1/metrics", - httpService(metricRequests, ExportMetricsServiceRequest.getDefaultInstance())); - sb.tls( - certificateExtension.heldCertificate.keyPair().getPrivate(), - certificateExtension.heldCertificate.certificate()); - } - }; - - @SuppressWarnings("unchecked") - private static HttpService httpService( - BlockingQueue queue, T defaultMessage) { - return (ctx, req) -> - HttpResponse.from( - req.aggregate() - .thenApply( - aggReq -> { - requestHeaders.add(aggReq.headers()); - try { - byte[] requestBody = - maybeGzipInflate(aggReq.headers(), aggReq.content().array()); - queue.add((T) defaultMessage.getParserForType().parseFrom(requestBody)); - } catch (IOException e) { - return HttpResponse.of(HttpStatus.BAD_REQUEST); - } - return HttpResponse.of(HttpStatus.OK); - })); - } - - private static byte[] maybeGzipInflate(RequestHeaders requestHeaders, byte[] content) - throws IOException { - if (!requestHeaders.contains("content-encoding", "gzip")) { - return content; - } - Buffer buffer = new Buffer(); - GzipSource gzipSource = new GzipSource(Okio.source(new ByteArrayInputStream(content))); - gzipSource.read(buffer, Integer.MAX_VALUE); - return buffer.readByteArray(); - } + public static final OtlpHttpServerExtension server = new OtlpHttpServerExtension(); @BeforeEach void setUp() { - traceRequests.clear(); - metricRequests.clear(); - requestHeaders.clear(); + server.reset(); GlobalOpenTelemetry.resetForTest(); } @@ -172,9 +63,9 @@ public void tearDown() { void configureExportersGeneral() { Map props = new HashMap<>(); props.put("otel.exporter.otlp.protocol", "http/protobuf"); + props.put("otel.exporter.otlp.endpoint", "https://localhost:" + server.httpsPort()); props.put( - "otel.exporter.otlp.endpoint", "https://" + canonicalHostName + ":" + server.httpsPort()); - props.put("otel.exporter.otlp.certificate", certificateExtension.filePath); + "otel.exporter.otlp.certificate", server.selfSignedCertificate.certificate().getPath()); props.put("otel.exporter.otlp.headers", "header-key=header-value"); props.put("otel.exporter.otlp.compression", "gzip"); props.put("otel.exporter.otlp.timeout", "15s"); @@ -195,8 +86,8 @@ void configureExportersGeneral() { .join(15, TimeUnit.SECONDS) .isSuccess()) .isTrue(); - assertThat(traceRequests).hasSize(1); - assertThat(requestHeaders) + assertThat(server.traceRequests).hasSize(1); + assertThat(server.requestHeaders) .anyMatch( headers -> headers.contains(":path", "/v1/traces") @@ -213,8 +104,8 @@ void configureExportersGeneral() { .join(15, TimeUnit.SECONDS) .isSuccess()) .isTrue(); - assertThat(metricRequests).hasSize(1); - assertThat(requestHeaders) + assertThat(server.metricRequests).hasSize(1); + assertThat(server.requestHeaders) .anyMatch( headers -> headers.contains(":path", "/v1/metrics") @@ -236,8 +127,10 @@ void configureSpanExporter() { props.put("otel.exporter.otlp.timeout", "10s"); props.put( "otel.exporter.otlp.traces.endpoint", - "https://" + canonicalHostName + ":" + server.httpsPort() + "/v1/traces"); - props.put("otel.exporter.otlp.traces.certificate", certificateExtension.filePath); + "https://localhost:" + server.httpsPort() + "/v1/traces"); + props.put( + "otel.exporter.otlp.traces.certificate", + server.selfSignedCertificate.certificate().getPath()); props.put("otel.exporter.otlp.traces.headers", "header-key=header-value"); props.put("otel.exporter.otlp.traces.compression", "gzip"); props.put("otel.exporter.otlp.traces.timeout", "15s"); @@ -258,8 +151,8 @@ void configureSpanExporter() { .join(10, TimeUnit.SECONDS) .isSuccess()) .isTrue(); - assertThat(traceRequests).hasSize(1); - assertThat(requestHeaders) + assertThat(server.traceRequests).hasSize(1); + assertThat(server.requestHeaders) .anyMatch( headers -> headers.contains(":path", "/v1/traces") @@ -281,8 +174,10 @@ public void configureMetricExporter() { props.put("otel.exporter.otlp.timeout", "10s"); props.put( "otel.exporter.otlp.metrics.endpoint", - "https://" + canonicalHostName + ":" + server.httpsPort() + "/v1/metrics"); - props.put("otel.exporter.otlp.metrics.certificate", certificateExtension.filePath); + "https://localhost:" + server.httpsPort() + "/v1/metrics"); + props.put( + "otel.exporter.otlp.metrics.certificate", + server.selfSignedCertificate.certificate().getPath()); props.put("otel.exporter.otlp.metrics.headers", "header-key=header-value"); props.put("otel.exporter.otlp.metrics.compression", "gzip"); props.put("otel.exporter.otlp.metrics.timeout", "15s"); @@ -302,8 +197,8 @@ public void configureMetricExporter() { .join(15, TimeUnit.SECONDS) .isSuccess()) .isTrue(); - assertThat(metricRequests).hasSize(1); - assertThat(requestHeaders) + assertThat(server.metricRequests).hasSize(1); + assertThat(server.requestHeaders) .anyMatch( headers -> headers.contains(":path", "/v1/metrics") @@ -367,9 +262,9 @@ private static MetricData generateFakeMetric() { void configuresGlobal() { System.setProperty("otel.exporter.otlp.protocol", "http/protobuf"); System.setProperty( - "otel.exporter.otlp.endpoint", - "https://" + canonicalHostName + ":" + server.httpsPort() + "/"); - System.setProperty("otel.exporter.otlp.certificate", certificateExtension.filePath); + "otel.exporter.otlp.endpoint", "https://localhost:" + server.httpsPort() + "/"); + System.setProperty( + "otel.exporter.otlp.certificate", server.selfSignedCertificate.certificate().getPath()); System.setProperty("otel.metric.export.interval", "1s"); GlobalOpenTelemetry.get().getTracer("test").spanBuilder("test").startSpan().end(); @@ -377,12 +272,12 @@ void configuresGlobal() { await() .untilAsserted( () -> { - assertThat(traceRequests).hasSize(1); + assertThat(server.traceRequests).hasSize(1); // Not well defined how many metric exports would have happened by now, check that // any did. Metrics are recorded by OtlpHttpSpanExporter, BatchSpanProcessor, and // potentially others. - assertThat(metricRequests).isNotEmpty(); + assertThat(server.metricRequests).isNotEmpty(); }); } } diff --git a/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpRetryTest.java b/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpRetryTest.java new file mode 100644 index 00000000000..b95c5ea337f --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpRetryTest.java @@ -0,0 +1,169 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.autoconfigure; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.common.collect.Lists; +import com.linecorp.armeria.common.HttpResponse; +import com.linecorp.armeria.common.HttpStatus; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.exporter.otlp.internal.retry.RetryPolicy; +import io.opentelemetry.exporter.otlp.internal.retry.RetryUtil; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.metrics.data.LongPointData; +import io.opentelemetry.sdk.metrics.data.LongSumData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.testing.trace.TestSpanData; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.function.Supplier; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class OtlpHttpRetryTest { + + private static final List SPAN_DATA = + Lists.newArrayList( + TestSpanData.builder() + .setHasEnded(true) + .setName("name") + .setStartEpochNanos(MILLISECONDS.toNanos(System.currentTimeMillis())) + .setEndEpochNanos(MILLISECONDS.toNanos(System.currentTimeMillis())) + .setKind(SpanKind.SERVER) + .setStatus(StatusData.error()) + .setTotalRecordedEvents(0) + .setTotalRecordedLinks(0) + .build()); + private static final List METRIC_DATA = + Lists.newArrayList( + MetricData.createLongSum( + Resource.empty(), + InstrumentationLibraryInfo.empty(), + "metric_name", + "metric_description", + "ms", + LongSumData.create( + false, + AggregationTemporality.CUMULATIVE, + Collections.singletonList( + LongPointData.create( + MILLISECONDS.toNanos(System.currentTimeMillis()), + MILLISECONDS.toNanos(System.currentTimeMillis()), + Attributes.of(stringKey("key"), "value"), + 10))))); + + @RegisterExtension + public static final OtlpHttpServerExtension server = new OtlpHttpServerExtension(); + + @Test + void configureSpanExporterRetryPolicy() { + Map props = new HashMap<>(); + props.put("otel.exporter.otlp.traces.protocol", "http/protobuf"); + props.put( + "otel.exporter.otlp.traces.endpoint", + "https://localhost:" + server.httpsPort() + "/v1/traces"); + props.put( + "otel.exporter.otlp.traces.certificate", + server.selfSignedCertificate.certificate().getPath()); + props.put("otel.experimental.exporter.otlp.retry.enabled", "true"); + SpanExporter spanExporter = + SpanExporterConfiguration.configureExporter( + "otlp", + DefaultConfigProperties.createForTest(props), + Collections.emptyMap(), + MeterProvider.noop()); + + testRetryableStatusCodes(() -> SPAN_DATA, spanExporter::export, server.traceRequests::size); + testDefaultRetryPolicy(() -> SPAN_DATA, spanExporter::export, server.traceRequests::size); + } + + @Test + void configureMetricExporterRetryPolicy() { + Map props = new HashMap<>(); + props.put("otel.exporter.otlp.metrics.protocol", "http/protobuf"); + props.put( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:" + server.httpsPort() + "/v1/metrics"); + props.put( + "otel.exporter.otlp.metrics.certificate", + server.selfSignedCertificate.certificate().getPath()); + props.put("otel.experimental.exporter.otlp.retry.enabled", "true"); + MetricExporter metricExporter = + MetricExporterConfiguration.configureOtlpMetrics( + DefaultConfigProperties.createForTest(props), SdkMeterProvider.builder()); + + testRetryableStatusCodes( + () -> METRIC_DATA, metricExporter::export, server.metricRequests::size); + testDefaultRetryPolicy(() -> METRIC_DATA, metricExporter::export, server.metricRequests::size); + } + + private static void testRetryableStatusCodes( + Supplier dataSupplier, + Function exporter, + Supplier serverRequestCountSupplier) { + + List statusCodes = Arrays.asList(200, 400, 401, 403, 429, 500, 501, 502, 503); + + for (Integer code : statusCodes) { + server.reset(); + + server.responses.add(HttpResponse.of(HttpStatus.valueOf(code))); + server.responses.add(HttpResponse.of(HttpStatus.OK)); + + CompletableResultCode resultCode = + exporter.apply(dataSupplier.get()).join(10, TimeUnit.SECONDS); + boolean retryable = code != 200 && RetryUtil.retryableHttpResponseCodes().contains(code); + boolean expectedResult = retryable || code == 200; + assertThat(resultCode.isSuccess()) + .as( + "status code %s should export %s", + code, expectedResult ? "successfully" : "unsuccessfully") + .isEqualTo(expectedResult); + int expectedRequests = retryable ? 2 : 1; + assertThat(serverRequestCountSupplier.get()) + .as("status code %s should make %s requests", code, expectedRequests) + .isEqualTo(expectedRequests); + } + } + + private static void testDefaultRetryPolicy( + Supplier dataSupplier, + Function exporter, + Supplier serverRequestCountSupplier) { + server.reset(); + + // Set the server to fail with a retryable status code for the max attempts + int maxAttempts = RetryPolicy.getDefault().getMaxAttempts(); + int retryableCode = 503; + for (int i = 0; i < maxAttempts; i++) { + server.responses.add(HttpResponse.of(retryableCode)); + } + + // Result should be failure, sever should have received maxAttempts requests + CompletableResultCode resultCode = + exporter.apply(dataSupplier.get()).join(10, TimeUnit.SECONDS); + assertThat(resultCode.isSuccess()).isFalse(); + assertThat(serverRequestCountSupplier.get()).isEqualTo(maxAttempts); + } +} diff --git a/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpServerExtension.java b/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpServerExtension.java new file mode 100644 index 00000000000..642bd1d0dc9 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testOtlpHttp/java/io/opentelemetry/sdk/autoconfigure/OtlpHttpServerExtension.java @@ -0,0 +1,95 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.autoconfigure; + +import com.google.protobuf.Message; +import com.linecorp.armeria.common.HttpResponse; +import com.linecorp.armeria.common.HttpStatus; +import com.linecorp.armeria.common.RequestHeaders; +import com.linecorp.armeria.internal.common.util.SelfSignedCertificate; +import com.linecorp.armeria.server.HttpService; +import com.linecorp.armeria.server.ServerBuilder; +import com.linecorp.armeria.testing.junit5.server.ServerExtension; +import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest; +import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.util.ArrayDeque; +import java.util.Queue; +import okio.Buffer; +import okio.GzipSource; +import okio.Okio; + +class OtlpHttpServerExtension extends ServerExtension { + + final SelfSignedCertificate selfSignedCertificate; + + final Queue traceRequests = new ArrayDeque<>(); + final Queue metricRequests = new ArrayDeque<>(); + final Queue responses = new ArrayDeque<>(); + final Queue requestHeaders = new ArrayDeque<>(); + + OtlpHttpServerExtension() { + try { + selfSignedCertificate = new SelfSignedCertificate(); + } catch (CertificateException e) { + throw new IllegalStateException("Unable to setup certificate.", e); + } + } + + @Override + protected void configure(ServerBuilder sb) { + sb.service( + "/v1/traces", + httpService(traceRequests, ExportTraceServiceRequest.getDefaultInstance())) + .service( + "/v1/metrics", + httpService(metricRequests, ExportMetricsServiceRequest.getDefaultInstance())); + sb.tls(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()); + } + + @SuppressWarnings("unchecked") + private HttpService httpService(Queue queue, T defaultMessage) { + return (ctx, req) -> + HttpResponse.from( + req.aggregate() + .thenApply( + aggReq -> { + requestHeaders.add(aggReq.headers()); + try { + byte[] requestBody = + maybeGzipInflate(aggReq.headers(), aggReq.content().array()); + queue.add((T) defaultMessage.getParserForType().parseFrom(requestBody)); + } catch (IOException e) { + return HttpResponse.of(HttpStatus.BAD_REQUEST); + } + HttpResponse response = + responses.peek() != null + ? responses.poll() + : HttpResponse.of(HttpStatus.OK); + return response; + })); + } + + private static byte[] maybeGzipInflate(RequestHeaders requestHeaders, byte[] content) + throws IOException { + if (!requestHeaders.contains("content-encoding", "gzip")) { + return content; + } + Buffer buffer = new Buffer(); + GzipSource gzipSource = new GzipSource(Okio.source(new ByteArrayInputStream(content))); + gzipSource.read(buffer, Integer.MAX_VALUE); + return buffer.readByteArray(); + } + + void reset() { + traceRequests.clear(); + metricRequests.clear(); + requestHeaders.clear(); + responses.clear(); + } +}