From 405830accb6da2af2aeac6c5e1bb68a5f4e52e34 Mon Sep 17 00:00:00 2001 From: Radek Stankiewicz Date: Mon, 8 Jun 2026 14:45:35 +0200 Subject: [PATCH] Align gcpauth extension implementation with ability to turn it off easily while still being added as dependency. --- .../beam/gradle/BeamModulePlugin.groovy | 1 + .../build.gradle | 1 + .../gcp/auth/ConfigurableOption.java | 1 + ...thAutoConfigurationCustomizerProvider.java | 196 +++++++------ ...toConfigurationCustomizerProviderTest.java | 276 +++++++++++------- 5 files changed, 282 insertions(+), 193 deletions(-) diff --git a/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy b/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy index 9f34fb54e47b..61dbfa518b43 100644 --- a/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy +++ b/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy @@ -853,6 +853,7 @@ class BeamModulePlugin implements Plugin { log4j2_log4j12_api : "org.apache.logging.log4j:log4j-1.2-api:$log4j2_version", mockito_core : "org.mockito:mockito-core:4.11.0", mockito_inline : "org.mockito:mockito-inline:4.11.0", + mockito_junit_jupiter : "org.mockito:mockito-junit-jupiter:4.11.0", mongo_java_driver : "org.mongodb:mongodb-driver-sync:5.5.0", mongo_bson : "org.mongodb:bson:5.5.0", mongodb_driver_core : "org.mongodb:mongodb-driver-core:5.5.0", diff --git a/sdks/java/extensions/opentelemetry-gcp-auth-extension/build.gradle b/sdks/java/extensions/opentelemetry-gcp-auth-extension/build.gradle index 1b08b867b291..a1e18805bf3f 100644 --- a/sdks/java/extensions/opentelemetry-gcp-auth-extension/build.gradle +++ b/sdks/java/extensions/opentelemetry-gcp-auth-extension/build.gradle @@ -37,6 +37,7 @@ dependencies { testImplementation library.java.junit testImplementation library.java.mockito_core testImplementation library.java.mockito_inline + testImplementation library.java.mockito_junit_jupiter testImplementation library.java.jupiter_api testImplementation library.java.jupiter_params testRuntimeOnly library.java.jupiter_engine diff --git a/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/main/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/ConfigurableOption.java b/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/main/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/ConfigurableOption.java index e18e5693e3a1..8cdbe00af6ef 100644 --- a/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/main/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/ConfigurableOption.java +++ b/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/main/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/ConfigurableOption.java @@ -61,6 +61,7 @@ enum ConfigurableOption { *
  • {@code metrics} - Enables authentication for metric exports. *
  • {@code traces} - Enables authentication for trace exports. *
  • {@code all} - Enables authentication for all exports. + *
  • {@code none} - Disables authentication for all exports. * * *

    The values are case-sensitive. Whitespace around commas and values is ignored. Can be diff --git a/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/main/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java b/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/main/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java index ce2b142591bd..453fb5717008 100644 --- a/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/main/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java +++ b/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/main/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java @@ -20,15 +20,20 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey; import static java.util.Arrays.stream; import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import com.google.auth.oauth2.GoogleCredentials; import com.google.auto.service.AutoService; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; +import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; +import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -41,8 +46,9 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import org.apache.beam.sdk.annotations.Internal; import org.apache.beam.sdk.extensions.opentelemetry.gcp.auth.GoogleAuthException.Reason; @@ -62,25 +68,34 @@ * @see AutoConfigurationCustomizerProvider * @see GoogleCredentials */ -@AutoService(AutoConfigurationCustomizerProvider.class) @Internal +@AutoService(AutoConfigurationCustomizerProvider.class) public class GcpAuthAutoConfigurationCustomizerProvider implements AutoConfigurationCustomizerProvider { + private static final Logger LOG = + Logger.getLogger(GcpAuthAutoConfigurationCustomizerProvider.class.getName()); + private static final String SIGNAL_TARGET_WARNING_FIX_SUGGESTION = + String.format( + "You may safely ignore this warning if it is intentional, otherwise please configure the '%s' by exporting valid values to environment variable: %s or by setting valid values in system property: %s.", + ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getUserReadableName(), + ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getEnvironmentVariable(), + ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty()); + static final String QUOTA_USER_PROJECT_HEADER = "x-goog-user-project"; static final String GCP_USER_PROJECT_ID_KEY = "gcp.project_id"; static final String SIGNAL_TYPE_TRACES = "traces"; static final String SIGNAL_TYPE_METRICS = "metrics"; static final String SIGNAL_TYPE_ALL = "all"; - - private @Nullable GoogleCredentials credentials; + static final String SIGNAL_TYPE_NONE = "none"; /** * Customizes the provided {@link AutoConfigurationCustomizer} such that authenticated exports to * GCP Telemetry API are possible from the configured OTLP exporter. * - *

    This method performs the following: + *

    This method attempts to retrieve Google Application Default Credentials (ADC) and performs + * the following: * *

      *
    • Verifies whether the configured OTLP endpoint (base or signal specific) is a known GCP @@ -99,10 +114,32 @@ public class GcpAuthAutoConfigurationCustomizerProvider */ @Override public void customize(@Nonnull AutoConfigurationCustomizer autoConfiguration) { + java.util.function.Supplier credentialsSupplier = + new java.util.function.Supplier() { + private @javax.annotation.Nullable GoogleCredentials credentials; + + @Override + public synchronized GoogleCredentials get() { + if (credentials == null) { + try { + credentials = GoogleCredentials.getApplicationDefault(); + } catch (IOException e) { + throw new GoogleAuthException(Reason.FAILED_ADC_RETRIEVAL, e); + } + } + return credentials; + } + }; autoConfiguration - .addSpanExporterCustomizer(this::customizeSpanExporter) - .addMetricExporterCustomizer(this::customizeMetricExporter) - .addResourceCustomizer(this::customizeResource); + .addSpanExporterCustomizer( + (spanExporter, configProperties) -> + customizeSpanExporter(spanExporter, credentialsSupplier, configProperties)) + .addMetricExporterCustomizer( + (metricExporter, configProperties) -> + customizeMetricExporter(metricExporter, credentialsSupplier, configProperties)) + .addResourceCustomizer( + (resource, configProperties) -> + customizeResource(resource, credentialsSupplier, configProperties)); } @Override @@ -110,136 +147,106 @@ public int order() { return Integer.MAX_VALUE - 1; } - private synchronized GoogleCredentials getCredentials() { - if (credentials == null) { - try { - credentials = GoogleCredentials.getApplicationDefault(); - } catch (IOException e) { - throw new GoogleAuthException(Reason.FAILED_ADC_RETRIEVAL, e); - } - } - return credentials; - } - - private SpanExporter customizeSpanExporter( - SpanExporter exporter, ConfigProperties configProperties) { + private static SpanExporter customizeSpanExporter( + SpanExporter exporter, + java.util.function.Supplier credentialsSupplier, + ConfigProperties configProperties) { if (isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { - return addAuthorizationHeaders(exporter, configProperties); + return addAuthorizationHeaders(exporter, credentialsSupplier.get(), configProperties); + } else { + String[] params = { + SIGNAL_TYPE_TRACES, SIGNAL_TYPE_NONE, SIGNAL_TARGET_WARNING_FIX_SUGGESTION + }; + LOG.log( + Level.WARNING, + "GCP Authentication Extension is not configured for signal type: {0} or is configured with signal type: {1}. {2}", + params); } return exporter; } - private MetricExporter customizeMetricExporter( - MetricExporter exporter, ConfigProperties configProperties) { + private static MetricExporter customizeMetricExporter( + MetricExporter exporter, + java.util.function.Supplier credentialsSupplier, + ConfigProperties configProperties) { if (isSignalTargeted(SIGNAL_TYPE_METRICS, configProperties)) { - return addAuthorizationHeaders(exporter, configProperties); + return addAuthorizationHeaders(exporter, credentialsSupplier.get(), configProperties); + } else { + String[] params = { + SIGNAL_TYPE_METRICS, SIGNAL_TYPE_NONE, SIGNAL_TARGET_WARNING_FIX_SUGGESTION + }; + LOG.log( + Level.WARNING, + "GCP Authentication Extension is not configured for signal type: {0} or is configured with signal type: {1}. {2}", + params); } return exporter; } // Checks if the auth extension is configured to target the passed signal for authentication. private static boolean isSignalTargeted(String checkSignal, ConfigProperties configProperties) { - String endpoint = configProperties.getString("otel.exporter.otlp." + checkSignal + ".endpoint"); - if (endpoint == null) { - endpoint = configProperties.getString("otel.exporter.otlp.endpoint"); - } - if (endpoint == null) { - return false; - } - - try { - java.net.URI uri = new java.net.URI(endpoint); - String host = uri.getHost(); - String scheme = uri.getScheme(); - if (host == null - || scheme == null - || !scheme.equalsIgnoreCase("https") - || (!host.equalsIgnoreCase("telemetry.googleapis.com") - && !host.equalsIgnoreCase("telemetry.mtls.googleapis.com"))) { - return false; - } - } catch (java.net.URISyntaxException e) { - return false; - } - String userSpecifiedTargetedSignals = ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getConfiguredValueWithFallback( configProperties, () -> SIGNAL_TYPE_ALL); - return stream(userSpecifiedTargetedSignals.split(",")) - .map(String::trim) - .anyMatch( - targetedSignal -> - targetedSignal.equals(checkSignal) || targetedSignal.equals(SIGNAL_TYPE_ALL)); - } - - private boolean isAnySignalTargeted(ConfigProperties configProperties) { - return isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties) - || isSignalTargeted(SIGNAL_TYPE_METRICS, configProperties); + List targetedSignals = + stream(userSpecifiedTargetedSignals.split(",")).map(String::trim).collect(toList()); + if (targetedSignals.contains(SIGNAL_TYPE_NONE)) { + return false; + } + return targetedSignals.contains(checkSignal) || targetedSignals.contains(SIGNAL_TYPE_ALL); } // Adds authorization headers to the calls made by the OtlpGrpcSpanExporter and // OtlpHttpSpanExporter. - private SpanExporter addAuthorizationHeaders( - SpanExporter exporter, ConfigProperties configProperties) { + private static SpanExporter addAuthorizationHeaders( + SpanExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { if (exporter instanceof OtlpHttpSpanExporter) { - SpanExporter result = + OtlpHttpSpanExporterBuilder builder = ((OtlpHttpSpanExporter) exporter) .toBuilder() - .setHeaders(() -> getRequiredHeaderMap(configProperties)) - .build(); - exporter.shutdown(); - return result; + .setHeaders(() -> getRequiredHeaderMap(credentials, configProperties)); + return builder.build(); } else if (exporter instanceof OtlpGrpcSpanExporter) { - SpanExporter result = + OtlpGrpcSpanExporterBuilder builder = ((OtlpGrpcSpanExporter) exporter) .toBuilder() - .setHeaders(() -> getRequiredHeaderMap(configProperties)) - .build(); - exporter.shutdown(); - return result; + .setHeaders(() -> getRequiredHeaderMap(credentials, configProperties)); + return builder.build(); } return exporter; } // Adds authorization headers to the calls made by the OtlpGrpcMetricExporter and // OtlpHttpMetricExporter. - private MetricExporter addAuthorizationHeaders( - MetricExporter exporter, ConfigProperties configProperties) { + private static MetricExporter addAuthorizationHeaders( + MetricExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { if (exporter instanceof OtlpHttpMetricExporter) { - MetricExporter result = + OtlpHttpMetricExporterBuilder builder = ((OtlpHttpMetricExporter) exporter) .toBuilder() - .setHeaders(() -> getRequiredHeaderMap(configProperties)) - .build(); - exporter.shutdown(); - return result; + .setHeaders(() -> getRequiredHeaderMap(credentials, configProperties)); + return builder.build(); } else if (exporter instanceof OtlpGrpcMetricExporter) { - MetricExporter result = + OtlpGrpcMetricExporterBuilder builder = ((OtlpGrpcMetricExporter) exporter) .toBuilder() - .setHeaders(() -> getRequiredHeaderMap(configProperties)) - .build(); - exporter.shutdown(); - return result; + .setHeaders(() -> getRequiredHeaderMap(credentials, configProperties)); + return builder.build(); } return exporter; } - private Map getRequiredHeaderMap(ConfigProperties configProperties) { - GoogleCredentials creds = getCredentials(); + private static Map getRequiredHeaderMap( + GoogleCredentials credentials, ConfigProperties configProperties) { Map> gcpHeaders; try { // this also refreshes the credentials, if required - gcpHeaders = creds.getRequestMetadata(); + gcpHeaders = credentials.getRequestMetadata(); } catch (IOException e) { throw new GoogleAuthException(Reason.FAILED_ADC_REFRESH, e); } - if (gcpHeaders == null) { - return Map.of(); - } Map flattenedHeaders = gcpHeaders.entrySet().stream() - .filter(entry -> entry.getKey() != null && entry.getValue() != null) .collect( toMap( Map.Entry::getKey, @@ -262,16 +269,19 @@ private Map getRequiredHeaderMap(ConfigProperties configProperti } // Updates the current resource with the attributes required for ingesting OTLP data on GCP. - private Resource customizeResource(Resource resource, ConfigProperties configProperties) { - if (!isAnySignalTargeted(configProperties)) { + private static Resource customizeResource( + Resource resource, + java.util.function.Supplier credentialsSupplier, + ConfigProperties configProperties) { + if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties) + && !isSignalTargeted(SIGNAL_TYPE_METRICS, configProperties)) { return resource; } - String gcpProjectId; try { gcpProjectId = ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue(configProperties); } catch (ConfigurationException e) { - gcpProjectId = getCredentials().getProjectId(); + gcpProjectId = credentialsSupplier.get().getProjectId(); if (gcpProjectId == null || gcpProjectId.isEmpty()) { throw e; } diff --git a/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/test/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java b/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/test/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java index e1db55c3635b..92aa72c2a79d 100644 --- a/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/test/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java +++ b/sdks/java/extensions/opentelemetry-gcp-auth-extension/src/test/java/org/apache/beam/sdk/extensions/opentelemetry/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java @@ -23,7 +23,6 @@ import static org.apache.beam.sdk.extensions.opentelemetry.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_ALL; import static org.apache.beam.sdk.extensions.opentelemetry.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_METRICS; import static org.apache.beam.sdk.extensions.opentelemetry.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_TRACES; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -58,6 +57,7 @@ import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.metrics.data.LongPointData; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.export.MetricExporter; import io.opentelemetry.sdk.trace.data.SpanData; @@ -80,9 +80,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableMap; +import org.junit.Assert; 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; @@ -92,12 +94,14 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.stubbing.Answer; /** * Copied from open-telemetry. Link: * https://github.com/open-telemetry/opentelemetry-java-contrib/blob/main/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java */ +@ExtendWith(MockitoExtension.class) class GcpAuthAutoConfigurationCustomizerProviderTest { private static final String DUMMY_GCP_RESOURCE_PROJECT_ID = "my-gcp-resource-project-id"; @@ -109,36 +113,37 @@ class GcpAuthAutoConfigurationCustomizerProviderTest { @Captor private ArgumentCaptor>> traceHeaderSupplierCaptor; @Captor private ArgumentCaptor>> metricHeaderSupplierCaptor; - private static final ImmutableMap DEFAULT_OTEL_PROPERTIES_SPAN_EXPORTER = - ImmutableMap.builder() - .put("otel.exporter.otlp.traces.endpoint", "https://telemetry.googleapis.com/v1/traces") - .put("otel.traces.exporter", "otlp") - .put("otel.metrics.exporter", "none") - .put("otel.logs.exporter", "none") - .put("otel.resource.attributes", "foo=bar") - .build(); - - private static final ImmutableMap DEFAULT_OTEL_PROPERTIES_METRIC_EXPORTER = - ImmutableMap.builder() - .put("otel.exporter.otlp.metrics.endpoint", "https://telemetry.googleapis.com/v1/metrics") - .put("otel.traces.exporter", "none") - .put("otel.metrics.exporter", "otlp") - .put("otel.logs.exporter", "none") - .put("otel.resource.attributes", "foo=bar") - .build(); + private static final ImmutableMap defaultOtelPropertiesSpanExporter = + ImmutableMap.of( + "otel.exporter.otlp.traces.endpoint", + "https://telemetry.googleapis.com/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "none", + "otel.logs.exporter", + "none", + "otel.resource.attributes", + "foo=bar"); + + private static final ImmutableMap defaultOtelPropertiesMetricExporter = + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://telemetry.googleapis.com/v1/metrics", + "otel.traces.exporter", + "none", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none", + "otel.resource.attributes", + "foo=bar"); @BeforeEach public void setup() { MockitoAnnotations.openMocks(this); } - @AfterEach - public void teardown() { - System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty()); - System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getSystemProperty()); - System.clearProperty(ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty()); - } - // TODO: Use parameterized test for testing traces customizer for http & grpc. @Test void testTraceCustomizerOtlpHttp() { @@ -236,7 +241,6 @@ void testTraceCustomizerOtlpGrpc() { .isTrue(); Mockito.verify(mockOtlpGrpcSpanExporter, Mockito.atLeast(1)).export(Mockito.anyCollection()); - assertThat(exportedSpans).isNotEmpty(); for (SpanData spanData : exportedSpans) { assertThat(spanData.getResource().getAttributes().asMap()) @@ -249,6 +253,7 @@ void testTraceCustomizerOtlpGrpc() { } } + // TODO: Use parameterized test for testing metrics customizer for http & grpc. @Test void testMetricCustomizerOtlpHttp() { // Set resource project system property @@ -289,7 +294,6 @@ void testMetricCustomizerOtlpHttp() { Mockito.verify(mockOtlpHttpMetricExporter, Mockito.atLeast(1)) .export(Mockito.anyCollection()); - assertThat(exportedMetrics).isNotEmpty(); for (MetricData metricData : exportedMetrics) { assertThat(metricData.getResource().getAttributes().asMap()) @@ -298,9 +302,8 @@ void testMetricCustomizerOtlpHttp() { assertThat(metricData.getResource().getAttributes().asMap()) .containsEntry(AttributeKey.stringKey("foo"), "bar"); assertThat(metricData.getLongSumData().getPoints()).isNotEmpty(); - for (io.opentelemetry.sdk.metrics.data.PointData pointData : - metricData.getLongSumData().getPoints()) { - assertThat(pointData.getAttributes().asMap()) + for (LongPointData longPointData : metricData.getLongSumData().getPoints()) { + assertThat(longPointData.getAttributes().asMap()) .containsKey(AttributeKey.longKey("work_loop")); } } @@ -347,7 +350,6 @@ void testMetricCustomizerOtlpGrpc() { Mockito.verify(mockOtlpGrpcMetricExporter, Mockito.atLeast(1)) .export(Mockito.anyCollection()); - assertThat(exportedMetrics).isNotEmpty(); for (MetricData metricData : exportedMetrics) { assertThat(metricData.getResource().getAttributes().asMap()) @@ -356,9 +358,8 @@ void testMetricCustomizerOtlpGrpc() { assertThat(metricData.getResource().getAttributes().asMap()) .containsEntry(AttributeKey.stringKey("foo"), "bar"); assertThat(metricData.getLongSumData().getPoints()).isNotEmpty(); - for (io.opentelemetry.sdk.metrics.data.PointData pointData : - metricData.getLongSumData().getPoints()) { - assertThat(pointData.getAttributes().asMap()) + for (LongPointData longPointData : metricData.getLongSumData().getPoints()) { + assertThat(longPointData.getAttributes().asMap()) .containsKey(AttributeKey.longKey("work_loop")); } } @@ -375,8 +376,7 @@ void testCustomizerFailWithMissingResourceProject() { googleCredentialsMockedStatic .when(GoogleCredentials::getApplicationDefault) .thenReturn(mockedGoogleCredentials); - - assertThrows( + Assert.assertThrows( ConfigurationException.class, () -> buildOpenTelemetrySdkWithExporter(mockOtlpGrpcSpanExporter)); } @@ -457,12 +457,16 @@ void testQuotaProjectBehavior(QuotaProjectIdTestBehavior testCase) throws IOExce } } + @AfterEach + void clearProperties() { + System.clearProperty("google.cloud.project"); + System.clearProperty("google.otel.auth.target.signals"); + } + @ParameterizedTest @MethodSource("provideProjectIdBehaviorTestCases") @SuppressWarnings("CannotMockMethod") void testProjectIdBehavior(ProjectIdTestBehavior testCase) throws IOException { - System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty()); - System.clearProperty(ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty()); // configure environment according to test case String userSpecifiedProjectId = testCase.getUserSpecifiedProjectId(); @@ -507,7 +511,7 @@ void testProjectIdBehavior(ProjectIdTestBehavior testCase) throws IOException { if (testCase.getExpectedToThrow()) { // expect exception to be thrown when project ID is not available - assertThrows( + Assert.assertThrows( ConfigurationException.class, () -> buildOpenTelemetrySdkWithExporter(mockOtlpGrpcSpanExporter)); // verify getProjectId() was called to attempt fallback @@ -626,14 +630,14 @@ private static Stream provideTargetSignalBehaviorTestCases() { Arguments.of( TargetSignalBehavior.builder() .setConfiguredTargetSignals("traces") - .setUserSpecifiedOtelProperties(DEFAULT_OTEL_PROPERTIES_SPAN_EXPORTER) + .setUserSpecifiedOtelProperties(defaultOtelPropertiesSpanExporter) .setExpectedIsMetricsSignalModified(false) .setExpectedIsTraceSignalModified(true) .build()), Arguments.of( TargetSignalBehavior.builder() .setConfiguredTargetSignals("metrics") - .setUserSpecifiedOtelProperties(DEFAULT_OTEL_PROPERTIES_METRIC_EXPORTER) + .setUserSpecifiedOtelProperties(defaultOtelPropertiesMetricExporter) .setExpectedIsMetricsSignalModified(true) .setExpectedIsTraceSignalModified(false) .build()), @@ -641,17 +645,17 @@ private static Stream provideTargetSignalBehaviorTestCases() { TargetSignalBehavior.builder() .setConfiguredTargetSignals("all") .setUserSpecifiedOtelProperties( - ImmutableMap.builder() - .put( - "otel.exporter.otlp.metrics.endpoint", - "https://telemetry.googleapis.com/v1/metrics") - .put( - "otel.exporter.otlp.traces.endpoint", - "https://telemetry.googleapis.com/v1/traces") - .put("otel.traces.exporter", "otlp") - .put("otel.metrics.exporter", "otlp") - .put("otel.logs.exporter", "none") - .build()) + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:4813/v1/metrics", + "otel.exporter.otlp.traces.endpoint", + "https://localhost:4813/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none")) .setExpectedIsMetricsSignalModified(true) .setExpectedIsTraceSignalModified(true) .build()), @@ -659,17 +663,17 @@ private static Stream provideTargetSignalBehaviorTestCases() { TargetSignalBehavior.builder() .setConfiguredTargetSignals("metrics, traces") .setUserSpecifiedOtelProperties( - ImmutableMap.builder() - .put( - "otel.exporter.otlp.metrics.endpoint", - "https://telemetry.googleapis.com/v1/metrics") - .put( - "otel.exporter.otlp.traces.endpoint", - "https://telemetry.googleapis.com/v1/traces") - .put("otel.traces.exporter", "otlp") - .put("otel.metrics.exporter", "otlp") - .put("otel.logs.exporter", "none") - .build()) + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:4813/v1/metrics", + "otel.exporter.otlp.traces.endpoint", + "https://localhost:4813/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none")) .setExpectedIsMetricsSignalModified(true) .setExpectedIsTraceSignalModified(true) .build()), @@ -677,17 +681,17 @@ private static Stream provideTargetSignalBehaviorTestCases() { TargetSignalBehavior.builder() .setConfiguredTargetSignals("") .setUserSpecifiedOtelProperties( - ImmutableMap.builder() - .put( - "otel.exporter.otlp.metrics.endpoint", - "https://telemetry.googleapis.com/v1/metrics") - .put( - "otel.exporter.otlp.traces.endpoint", - "https://telemetry.googleapis.com/v1/traces") - .put("otel.traces.exporter", "otlp") - .put("otel.metrics.exporter", "otlp") - .put("otel.logs.exporter", "none") - .build()) + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:4813/v1/metrics", + "otel.exporter.otlp.traces.endpoint", + "https://localhost:4813/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none")) .setExpectedIsMetricsSignalModified(true) .setExpectedIsTraceSignalModified(true) .build()), @@ -697,9 +701,9 @@ private static Stream provideTargetSignalBehaviorTestCases() { .setUserSpecifiedOtelProperties( ImmutableMap.of( "otel.exporter.otlp.metrics.endpoint", - "https://telemetry.googleapis.com/v1/metrics", + "https://localhost:4813/v1/metrics", "otel.exporter.otlp.traces.endpoint", - "https://telemetry.googleapis.com/v1/traces", + "https://localhost:4813/v1/traces", "otel.traces.exporter", "none", "otel.metrics.exporter", @@ -713,17 +717,17 @@ private static Stream provideTargetSignalBehaviorTestCases() { TargetSignalBehavior.builder() .setConfiguredTargetSignals("metric, trace") .setUserSpecifiedOtelProperties( - ImmutableMap.builder() - .put( - "otel.exporter.otlp.metrics.endpoint", - "https://telemetry.googleapis.com/v1/metrics") - .put( - "otel.exporter.otlp.traces.endpoint", - "https://telemetry.googleapis.com/v1/traces") - .put("otel.traces.exporter", "otlp") - .put("otel.metrics.exporter", "otlp") - .put("otel.logs.exporter", "none") - .build()) + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:4813/v1/metrics", + "otel.exporter.otlp.traces.endpoint", + "https://localhost:4813/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none")) .setExpectedIsMetricsSignalModified(false) .setExpectedIsTraceSignalModified(false) .build()), @@ -731,19 +735,91 @@ private static Stream provideTargetSignalBehaviorTestCases() { TargetSignalBehavior.builder() .setConfiguredTargetSignals("metrics, trace") .setUserSpecifiedOtelProperties( - ImmutableMap.builder() - .put( - "otel.exporter.otlp.metrics.endpoint", - "https://telemetry.googleapis.com/v1/metrics") - .put( - "otel.exporter.otlp.traces.endpoint", - "https://telemetry.googleapis.com/v1/traces") - .put("otel.traces.exporter", "otlp") - .put("otel.metrics.exporter", "otlp") - .put("otel.logs.exporter", "none") - .build()) + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:4813/v1/metrics", + "otel.exporter.otlp.traces.endpoint", + "https://localhost:4813/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none")) .setExpectedIsMetricsSignalModified(true) .setExpectedIsTraceSignalModified(false) + .build()), + Arguments.of( + TargetSignalBehavior.builder() + .setConfiguredTargetSignals("none") + .setUserSpecifiedOtelProperties( + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:4813/v1/metrics", + "otel.exporter.otlp.traces.endpoint", + "https://localhost:4813/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none")) + .setExpectedIsMetricsSignalModified(false) + .setExpectedIsTraceSignalModified(false) + .build()), + Arguments.of( + TargetSignalBehavior.builder() + .setConfiguredTargetSignals("metrics, trace, none") + .setUserSpecifiedOtelProperties( + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:4813/v1/metrics", + "otel.exporter.otlp.traces.endpoint", + "https://localhost:4813/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none")) + .setExpectedIsMetricsSignalModified(false) + .setExpectedIsTraceSignalModified(false) + .build()), + Arguments.of( + TargetSignalBehavior.builder() + .setConfiguredTargetSignals("all, none") + .setUserSpecifiedOtelProperties( + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:4813/v1/metrics", + "otel.exporter.otlp.traces.endpoint", + "https://localhost:4813/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none")) + .setExpectedIsMetricsSignalModified(false) + .setExpectedIsTraceSignalModified(false) + .build()), + Arguments.of( + TargetSignalBehavior.builder() + .setConfiguredTargetSignals("metrics, none") + .setUserSpecifiedOtelProperties( + ImmutableMap.of( + "otel.exporter.otlp.metrics.endpoint", + "https://localhost:4813/v1/metrics", + "otel.exporter.otlp.traces.endpoint", + "https://localhost:4813/v1/traces", + "otel.traces.exporter", + "otlp", + "otel.metrics.exporter", + "otlp", + "otel.logs.exporter", + "none")) + .setExpectedIsMetricsSignalModified(false) + .setExpectedIsTraceSignalModified(false) .build())); } @@ -1114,7 +1190,7 @@ private void prepareMockBehaviorForGoogleCredentials() { private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(SpanExporter spanExporter) { return buildOpenTelemetrySdkWithExporter( - spanExporter, OtlpHttpMetricExporter.getDefault(), DEFAULT_OTEL_PROPERTIES_SPAN_EXPORTER); + spanExporter, OtlpHttpMetricExporter.getDefault(), defaultOtelPropertiesSpanExporter); } @SuppressWarnings("UnusedMethod") @@ -1126,7 +1202,7 @@ private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter( private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(MetricExporter metricExporter) { return buildOpenTelemetrySdkWithExporter( - OtlpHttpSpanExporter.getDefault(), metricExporter, DEFAULT_OTEL_PROPERTIES_METRIC_EXPORTER); + OtlpHttpSpanExporter.getDefault(), metricExporter, defaultOtelPropertiesMetricExporter); } @SuppressWarnings("UnusedMethod")