diff --git a/CHANGELOG.md b/CHANGELOG.md
index dbf440dc00..a69df0af4e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -50,5 +50,12 @@ If your change does not need a CHANGELOG entry, add the "skip changelog" label t
([#1201](https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1201))
- Add support for new formal database semantic convention keys.
([#1162](https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1162))
+<<<<<<< HEAD
- Bump ADOT Java version to 2.20.0 and OTel deps to 2.20.1.
([#1246](https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1246))
+=======
+
+### Refactors
+- Refactor AwsMetricAttributesSpanExporter to an onEnding processor
+ ([#1250](https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1250))
+>>>>>>> f6008fb (Refactor AwsMetricAttributesSpanExporter to an onEnding processor)
diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/base/BaseHttpServerTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/base/BaseHttpServerTest.java
index ce55c23fe5..3fdba0e3a4 100644
--- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/base/BaseHttpServerTest.java
+++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/base/BaseHttpServerTest.java
@@ -52,7 +52,7 @@
public abstract class BaseHttpServerTest extends ContractTestBase {
/**
- * Assert span attributes inserted by the AwsMetricAttributesSpanExporter
+ * Assert span attributes inserted by the AwsAttributeGeneratingSpanProcessor
*
* @param resourceScopeSpans list of spans that were exported by the application
* @param method the http method that was used (GET, PUT, DELETE...)
diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java
index 3b6616564c..776de088f8 100644
--- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java
+++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java
@@ -79,7 +79,7 @@
*
Add AwsAttributeGeneratingSpanProcessor to add more attributes to all spans.
*
*
* You can control when these customizations are applied using the property
@@ -375,6 +375,9 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
// Construct and set local and remote attributes span processor
tracerProviderBuilder.addSpanProcessor(
AttributePropagatingSpanProcessorBuilder.create().build());
+ // Construct and set AWS Attribute Generating Span Processor
+ tracerProviderBuilder.addSpanProcessor(
+ AwsAttributeGeneratingSpanProcessorBuilder.create(ResourceHolder.getResource()).build());
// If running on Lambda, we just need to export 100% spans and skip generating any Application
// Signals metrics.
@@ -389,16 +392,9 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
.setEndpoint(tracesEndpoint)
.build();
- // Wrap the udp exporter with the AwsMetricsAttributesSpanExporter to add Application
- // Signals attributes to unsampled spans too
- SpanExporter appSignalsSpanExporter =
- AwsMetricAttributesSpanExporterBuilder.create(
- spanExporter, ResourceHolder.getResource())
- .build();
-
tracerProviderBuilder.addSpanProcessor(
AwsUnsampledOnlySpanProcessorBuilder.create()
- .setSpanExporter(appSignalsSpanExporter)
+ .setSpanExporter(spanExporter)
.setMaxExportBatchSize(LAMBDA_SPAN_EXPORT_BATCH_SIZE)
.build());
return tracerProviderBuilder;
@@ -498,12 +494,6 @@ SpanExporter customizeSpanExporter(SpanExporter spanExporter, ConfigProperties c
}
}
- if (isApplicationSignalsEnabled(configProps)) {
- spanExporter =
- AwsMetricAttributesSpanExporterBuilder.create(spanExporter, ResourceHolder.getResource())
- .build();
- }
-
if (this.sampler instanceof AwsXrayRemoteSampler) {
((AwsXrayRemoteSampler) this.sampler).setSpanExporter(spanExporter);
}
diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeGeneratingSpanProcessor.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeGeneratingSpanProcessor.java
new file mode 100644
index 0000000000..2c817a6267
--- /dev/null
+++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeGeneratingSpanProcessor.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.opentelemetry.javaagent.providers;
+
+import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SPAN_KIND;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.sdk.resources.Resource;
+import io.opentelemetry.sdk.trace.ReadWriteSpan;
+import io.opentelemetry.sdk.trace.ReadableSpan;
+import io.opentelemetry.sdk.trace.data.SpanData;
+import io.opentelemetry.sdk.trace.internal.ExtendedSpanProcessor;
+import java.util.Map;
+
+public class AwsAttributeGeneratingSpanProcessor implements ExtendedSpanProcessor {
+
+ private final MetricAttributeGenerator generator;
+ private final Resource resource;
+
+ public static AwsAttributeGeneratingSpanProcessor create(
+ MetricAttributeGenerator generator, Resource resource) {
+ return new AwsAttributeGeneratingSpanProcessor(generator, resource);
+ }
+
+ private AwsAttributeGeneratingSpanProcessor(
+ MetricAttributeGenerator generator, Resource resource) {
+ this.generator = generator;
+ this.resource = resource;
+ }
+
+ @Override
+ public void onStart(Context parentContext, ReadWriteSpan span) {}
+
+ @Override
+ public boolean isStartRequired() {
+ return false;
+ }
+
+ @Override
+ public void onEnding(ReadWriteSpan span) {
+ // If the map has no items, no modifications are required. If there is one item, it means the
+ // span either produces Service or Dependency metric attributes, and in either case we want to
+ // modify the span with them. If there are two items, the span produces both Service and
+ // Dependency metric attributes indicating the span is a local dependency root. The Service
+ // Attributes must be a subset of the Dependency, with the exception of AWS_SPAN_KIND. The
+ // knowledge that the span is a local root is more important than knowing that it is a
+ // Dependency metric, so we take all the Dependency metrics but replace AWS_SPAN_KIND with
+ // LOCAL_ROOT.
+ SpanData spanData = span.toSpanData();
+ Map attributeMap =
+ generator.generateMetricAttributeMapFromSpan(span.toSpanData(), resource);
+
+ boolean generatesServiceMetrics =
+ AwsSpanProcessingUtil.shouldGenerateServiceMetricAttributes(spanData);
+ boolean generatesDependencyMetrics =
+ AwsSpanProcessingUtil.shouldGenerateDependencyMetricAttributes(spanData);
+
+ if (generatesServiceMetrics && generatesDependencyMetrics) {
+ // Order matters: dependency metric attributes include AWS_SPAN_KIND key
+ span.setAllAttributes(attributeMap.get(MetricAttributeGenerator.DEPENDENCY_METRIC));
+ span.setAttribute(AWS_SPAN_KIND, AwsSpanProcessingUtil.LOCAL_ROOT);
+ } else if (generatesServiceMetrics) {
+ span.setAllAttributes(attributeMap.get(MetricAttributeGenerator.SERVICE_METRIC));
+ } else if (generatesDependencyMetrics) {
+ span.setAllAttributes(attributeMap.get(MetricAttributeGenerator.DEPENDENCY_METRIC));
+ }
+ }
+
+ @Override
+ public boolean isOnEndingRequired() {
+ return true;
+ }
+
+ @Override
+ public void onEnd(ReadableSpan span) {}
+
+ @Override
+ public boolean isEndRequired() {
+ return false;
+ }
+}
diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributesSpanExporterBuilder.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeGeneratingSpanProcessorBuilder.java
similarity index 62%
rename from awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributesSpanExporterBuilder.java
rename to awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeGeneratingSpanProcessorBuilder.java
index 7de8b00f2a..c5670a2b7e 100644
--- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributesSpanExporterBuilder.java
+++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeGeneratingSpanProcessorBuilder.java
@@ -19,43 +19,40 @@
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.opentelemetry.sdk.resources.Resource;
-import io.opentelemetry.sdk.trace.export.SpanExporter;
-public class AwsMetricAttributesSpanExporterBuilder {
+public class AwsAttributeGeneratingSpanProcessorBuilder {
// Defaults
private static final MetricAttributeGenerator DEFAULT_GENERATOR =
new AwsMetricAttributeGenerator();
// Required builder elements
- private final SpanExporter delegate;
private final Resource resource;
// Optional builder elements
private MetricAttributeGenerator generator = DEFAULT_GENERATOR;
- public static AwsMetricAttributesSpanExporterBuilder create(
- SpanExporter delegate, Resource resource) {
- return new AwsMetricAttributesSpanExporterBuilder(delegate, resource);
+ public static AwsAttributeGeneratingSpanProcessorBuilder create(Resource resource) {
+ return new AwsAttributeGeneratingSpanProcessorBuilder(resource);
}
- private AwsMetricAttributesSpanExporterBuilder(SpanExporter delegate, Resource resource) {
- this.delegate = delegate;
+ private AwsAttributeGeneratingSpanProcessorBuilder(Resource resource) {
this.resource = resource;
}
/**
- * Sets the generator used to generate attributes used spancs exported by the exporter. If unset,
+ * Sets the generator used to generate attributes added to spans in the processor. If unset,
* defaults to {@link #DEFAULT_GENERATOR}. Must not be null.
*/
@CanIgnoreReturnValue
- public AwsMetricAttributesSpanExporterBuilder setGenerator(MetricAttributeGenerator generator) {
+ public AwsAttributeGeneratingSpanProcessorBuilder setGenerator(
+ MetricAttributeGenerator generator) {
requireNonNull(generator, "generator");
this.generator = generator;
return this;
}
- public AwsMetricAttributesSpanExporter build() {
- return AwsMetricAttributesSpanExporter.create(delegate, generator, resource);
+ public AwsAttributeGeneratingSpanProcessor build() {
+ return AwsAttributeGeneratingSpanProcessor.create(generator, resource);
}
}
diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributesSpanExporter.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributesSpanExporter.java
deleted file mode 100644
index 0ff3e93c34..0000000000
--- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributesSpanExporter.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright Amazon.com, Inc. or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://aws.amazon.com/apache2.0
- *
- * or in the "license" file accompanying this file. This file is distributed
- * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package software.amazon.opentelemetry.javaagent.providers;
-
-import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SPAN_KIND;
-
-import io.opentelemetry.api.common.AttributeKey;
-import io.opentelemetry.api.common.Attributes;
-import io.opentelemetry.api.common.AttributesBuilder;
-import io.opentelemetry.sdk.common.CompletableResultCode;
-import io.opentelemetry.sdk.resources.Resource;
-import io.opentelemetry.sdk.trace.data.DelegatingSpanData;
-import io.opentelemetry.sdk.trace.data.SpanData;
-import io.opentelemetry.sdk.trace.export.SpanExporter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.annotation.concurrent.Immutable;
-
-/**
- * This exporter will update a span with metric attributes before exporting. It depends on a {@link
- * SpanExporter} being provided on instantiation, which the AwsSpanMetricsExporter will delegate
- * export to. Also, a {@link MetricAttributeGenerator} must be provided, which will provide a means
- * to determine attributes which should be applied to the span. Finally, a {@link Resource} must be
- * provided, which is used to generate metric attributes.
- *
- * This exporter should be coupled with the {@link AwsSpanMetricsProcessor} using the same {@link
- * MetricAttributeGenerator}. This will result in metrics and spans being produced with common
- * attributes.
- */
-@Immutable
-public class AwsMetricAttributesSpanExporter implements SpanExporter {
-
- private final SpanExporter delegate;
- private final MetricAttributeGenerator generator;
- private final Resource resource;
-
- /** Use {@link AwsMetricAttributesSpanExporterBuilder} to construct this exporter. */
- static AwsMetricAttributesSpanExporter create(
- SpanExporter delegate, MetricAttributeGenerator generator, Resource resource) {
- return new AwsMetricAttributesSpanExporter(delegate, generator, resource);
- }
-
- private AwsMetricAttributesSpanExporter(
- SpanExporter delegate, MetricAttributeGenerator generator, Resource resource) {
- this.delegate = delegate;
- this.generator = generator;
- this.resource = resource;
- }
-
- @Override
- public CompletableResultCode export(Collection spans) {
- List modifiedSpans = addMetricAttributes(spans);
- return delegate.export(modifiedSpans);
- }
-
- @Override
- public CompletableResultCode flush() {
- return delegate.flush();
- }
-
- @Override
- public CompletableResultCode shutdown() {
- return delegate.shutdown();
- }
-
- @Override
- public void close() {
- delegate.close();
- }
-
- private List addMetricAttributes(Collection spans) {
- List modifiedSpans = new ArrayList<>();
-
- for (SpanData span : spans) {
- // If the map has no items, no modifications are required. If there is one item, it means the
- // span either produces Service or Dependency metric attributes, and in either case we want to
- // modify the span with them. If there are two items, the span produces both Service and
- // Dependency metric attributes indicating the span is a local dependency root. The Service
- // Attributes must be a subset of the Dependency, with the exception of AWS_SPAN_KIND. The
- // knowledge that the span is a local root is more important that knowing that it is a
- // Dependency metric, so we take all the Dependency metrics but replace AWS_SPAN_KIND with
- // LOCAL_ROOT.
- Map attributeMap =
- generator.generateMetricAttributeMapFromSpan(span, resource);
- Attributes attributes = Attributes.empty();
-
- boolean generatesServiceMetrics =
- AwsSpanProcessingUtil.shouldGenerateServiceMetricAttributes(span);
- boolean generatesDependencyMetrics =
- AwsSpanProcessingUtil.shouldGenerateDependencyMetricAttributes(span);
-
- if (generatesServiceMetrics && generatesDependencyMetrics) {
- attributes =
- copyAttributesWithLocalRoot(
- attributeMap.get(MetricAttributeGenerator.DEPENDENCY_METRIC));
- } else if (generatesServiceMetrics) {
- attributes = attributeMap.get(MetricAttributeGenerator.SERVICE_METRIC);
- } else if (generatesDependencyMetrics) {
- attributes = attributeMap.get(MetricAttributeGenerator.DEPENDENCY_METRIC);
- }
-
- if (!attributes.isEmpty()) {
- span = wrapSpanWithAttributes(span, attributes);
- }
- modifiedSpans.add(span);
- }
-
- return modifiedSpans;
- }
-
- private Attributes copyAttributesWithLocalRoot(Attributes attributes) {
- AttributesBuilder builder = attributes.toBuilder();
- builder.remove(AWS_SPAN_KIND);
- builder.put(AWS_SPAN_KIND, AwsSpanProcessingUtil.LOCAL_ROOT);
- return builder.build();
- }
-
- /**
- * {@link #export} works with a {@link SpanData}, which does not permit modification. However, we
- * need to add derived metric attributes to the span. To work around this, we will wrap the
- * SpanData with a {@link DelegatingSpanData} that simply passes through all API calls, except for
- * those pertaining to Attributes, i.e. {@link SpanData#getAttributes()} and {@link
- * SpanData#getTotalAttributeCount} APIs.
- *
- * See https://github.com/open-telemetry/opentelemetry-specification/issues/1089 for more
- * context on this approach.
- */
- private static SpanData wrapSpanWithAttributes(SpanData span, Attributes attributes) {
- Attributes originalAttributes = span.getAttributes();
- Attributes replacementAttributes = originalAttributes.toBuilder().putAll(attributes).build();
-
- int newAttributeKeyCount = 0;
- for (Entry, Object> entry : attributes.asMap().entrySet()) {
- if (originalAttributes.get(entry.getKey()) == null) {
- newAttributeKeyCount++;
- }
- }
- int originalTotalAttributeCount = span.getTotalAttributeCount();
- int replacementTotalAttributeCount = originalTotalAttributeCount + newAttributeKeyCount;
-
- return new DelegatingSpanData(span) {
- @Override
- public Attributes getAttributes() {
- return replacementAttributes;
- }
-
- @Override
- public int getTotalAttributeCount() {
- return replacementTotalAttributeCount;
- }
- };
- }
-}
diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/MetricAttributeGenerator.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/MetricAttributeGenerator.java
index cb3a5f7cae..d94d73c9de 100644
--- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/MetricAttributeGenerator.java
+++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/MetricAttributeGenerator.java
@@ -23,7 +23,7 @@
/**
* Metric attribute generator defines an interface for classes that can generate specific attributes
* to be used by an {@link AwsSpanMetricsProcessor} to produce metrics and by {@link
- * AwsMetricAttributesSpanExporter} to wrap the original span.
+ * AwsAttributeGeneratingSpanProcessor} to update the original span.
*/
public interface MetricAttributeGenerator {
static final String SERVICE_METRIC = "Service";
diff --git a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerTest.java b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerTest.java
new file mode 100644
index 0000000000..0f1d9663b8
--- /dev/null
+++ b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerTest.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.opentelemetry.javaagent.providers;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+import static software.amazon.opentelemetry.javaagent.providers.AwsApplicationSignalsCustomizerProvider.*;
+
+import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
+import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
+import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
+import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
+import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
+import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
+import io.opentelemetry.sdk.logs.export.LogRecordExporter;
+import io.opentelemetry.sdk.trace.export.SpanExporter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import software.amazon.opentelemetry.javaagent.providers.exporter.otlp.aws.logs.OtlpAwsLogsExporter;
+import software.amazon.opentelemetry.javaagent.providers.exporter.otlp.aws.traces.OtlpAwsSpanExporter;
+
+@ExtendWith({MockitoExtension.class})
+public class AwsApplicationSignalsCustomizerTest {
+ private AwsApplicationSignalsCustomizerProvider provider;
+ private final LogRecordExporter defaultHttpLogsExporter = OtlpHttpLogRecordExporter.getDefault();
+ private final SpanExporter defaultHttpSpanExporter = OtlpHttpSpanExporter.getDefault();
+
+ @BeforeEach
+ void init() {
+ this.provider = new AwsApplicationSignalsCustomizerProvider();
+ }
+
+ @AfterEach
+ void reset() {}
+
+ @ParameterizedTest
+ @MethodSource("validSigv4LogsConfigProvider")
+ void testShouldEnableSigV4LogsExporterIfConfigIsCorrect(Map validSigv4Config) {
+ customizeExporterTest(
+ validSigv4Config,
+ defaultHttpLogsExporter,
+ this.provider::customizeLogsExporter,
+ OtlpAwsLogsExporter.class);
+ }
+
+ @ParameterizedTest
+ @MethodSource("invalidSigv4LogsConfigProvider")
+ void testShouldNotUseSigv4LogsExporter(Map invalidSigv4Config) {
+ customizeExporterTest(
+ invalidSigv4Config,
+ defaultHttpLogsExporter,
+ this.provider::customizeLogsExporter,
+ OtlpHttpLogRecordExporter.class);
+ }
+
+ @Test
+ void testShouldNotUseSigv4LogsExporterIfValidatorThrows() {
+ try (MockedStatic ignored = mockStatic(Pattern.class)) {
+ when(Pattern.compile(any())).thenThrow(PatternSyntaxException.class);
+ customizeExporterTest(
+ Map.of(
+ OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
+ "https://logs.us-east-1.amazonaws.com/v1/logs",
+ OTEL_EXPORTER_OTLP_LOGS_HEADERS,
+ "x-aws-log-group=test1,x-aws-log-stream=test2",
+ OTEL_EXPORTER_OTLP_LOGS_PROTOCOL,
+ "http/protobuf",
+ OTEL_LOGS_EXPORTER,
+ "otlp"),
+ defaultHttpSpanExporter,
+ this.provider::customizeSpanExporter,
+ OtlpHttpSpanExporter.class);
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("validSigv4TracesConfigProvider")
+ void testShouldEnableSigV4SpanExporterIfConfigIsCorrect(Map validSigv4Config) {
+ customizeExporterTest(
+ validSigv4Config,
+ defaultHttpSpanExporter,
+ this.provider::customizeSpanExporter,
+ OtlpAwsSpanExporter.class);
+ }
+
+ @ParameterizedTest
+ @MethodSource("invalidSigv4TracesConfigProvider")
+ void testShouldNotUseSigv4SpanExporter(Map invalidSigv4Config) {
+ customizeExporterTest(
+ invalidSigv4Config,
+ defaultHttpSpanExporter,
+ this.provider::customizeSpanExporter,
+ OtlpHttpSpanExporter.class);
+ }
+
+ @Test
+ void testShouldNotUseSigv4SpanExporterIfValidatorThrows() {
+ try (MockedStatic ignored = mockStatic(Pattern.class)) {
+ when(Pattern.compile(any())).thenThrow(PatternSyntaxException.class);
+ customizeExporterTest(
+ Map.of(
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
+ "http://xray.us-east-1.amazonaws.com/v1/traces",
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL,
+ "http/protobuf",
+ OTEL_TRACES_EXPORTER,
+ "otlp"),
+ defaultHttpSpanExporter,
+ this.provider::customizeSpanExporter,
+ OtlpHttpSpanExporter.class);
+ }
+ }
+
+ // This technically should never happen as the validator checks for the correct env variables. But
+ // just to be safe.
+ @Test
+ void testShouldThrowIllegalStateExceptionIfIncorrectSpanExporter() {
+ assertThrows(
+ IllegalStateException.class,
+ () ->
+ customizeExporterTest(
+ Map.of(
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
+ "https://xray.us-east-1.amazonaws.com/v1/traces",
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL,
+ "http/protobuf",
+ OTEL_TRACES_EXPORTER,
+ "otlp"),
+ OtlpGrpcSpanExporter.getDefault(),
+ this.provider::customizeSpanExporter,
+ OtlpHttpSpanExporter.class));
+ }
+
+ // This technically should never happen as the validator checks for the correct env variables
+ @Test
+ void testShouldThrowIllegalStateExceptionIfIncorrectLogsExporter() {
+ assertThrows(
+ IllegalStateException.class,
+ () ->
+ customizeExporterTest(
+ Map.of(
+ OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
+ "https://logs.us-east-1.amazonaws.com/v1/logs",
+ OTEL_EXPORTER_OTLP_LOGS_HEADERS,
+ "x-aws-log-group=test1,x-aws-log-stream=test2",
+ OTEL_EXPORTER_OTLP_LOGS_PROTOCOL,
+ "http/protobuf",
+ OTEL_LOGS_EXPORTER,
+ "otlp"),
+ OtlpGrpcLogRecordExporter.getDefault(),
+ this.provider::customizeLogsExporter,
+ OtlpHttpLogRecordExporter.class));
+ }
+
+ @Test
+ void testEnableApplicationSignalsSpanExporter() {
+ customizeExporterTest(
+ Map.of(
+ APPLICATION_SIGNALS_ENABLED_CONFIG,
+ "true",
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
+ "http://localhost:4318/v1/traces",
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL,
+ "http/protobuf",
+ OTEL_TRACES_EXPORTER,
+ "otlp"),
+ defaultHttpSpanExporter,
+ this.provider::customizeSpanExporter,
+ OtlpHttpSpanExporter.class);
+ }
+
+ @Test
+ void testSigv4ShouldNotDisableApplicationSignalsSpanExporter() {
+ customizeExporterTest(
+ Map.of(
+ APPLICATION_SIGNALS_ENABLED_CONFIG,
+ "true",
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
+ "https://xray.us-east-1.amazonaws.com/v1/traces",
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL,
+ "http/protobuf",
+ OTEL_TRACES_EXPORTER,
+ "otlp"),
+ defaultHttpSpanExporter,
+ this.provider::customizeSpanExporter,
+ OtlpAwsSpanExporter.class);
+ }
+
+ private static void customizeExporterTest(
+ Map config,
+ Exporter defaultExporter,
+ BiFunction executor,
+ Class> expectedExporterType) {
+
+ DefaultConfigProperties configProps = DefaultConfigProperties.createFromMap(config);
+ Exporter result = executor.apply(defaultExporter, configProps);
+ assertEquals(expectedExporterType, result.getClass());
+ }
+
+ static Stream validSigv4TracesConfigProvider() {
+ List