diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/ConfigurableOption.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/ConfigurableOption.java
index aba0ddf118..266156f829 100644
--- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/ConfigurableOption.java
+++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/ConfigurableOption.java
@@ -52,7 +52,23 @@ enum ConfigurableOption {
* configured using the environment variable `GOOGLE_OTEL_AUTH_TARGET_SIGNALS` or the system
* property `google.otel.auth.target.signals`.
*/
- GOOGLE_OTEL_AUTH_TARGET_SIGNALS("Target Signals for Google Authentication Extension");
+ GOOGLE_OTEL_AUTH_TARGET_SIGNALS("Target Signals for Google Authentication Extension"),
+
+ /**
+ * Specifies the path to a Google Cloud service account JSON key file. The path can be either
+ * absolute or relative to the current working directory. Can be configured using the environment
+ * variable `GOOGLE_CLOUD_CREDENTIALS_PATH` or the system property
+ * `google.cloud.credentials.path`.
+ */
+ GOOGLE_CLOUD_CREDENTIALS_PATH("Google Cloud Credentials Path"),
+
+ /**
+ * Specifies the raw JSON content of a Google Cloud service account key. This is useful when
+ * credentials are not stored in a file but are available as a string. Can be configured using the
+ * environment variable `GOOGLE_CLOUD_CREDENTIALS_JSON` or the system property
+ * `google.cloud.credentials.json`.
+ */
+ GOOGLE_CLOUD_CREDENTIALS_JSON("Google Cloud Credentials JSON String");
private final String userReadableName;
private final String environmentVariableName;
diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java
index dfde30796c..ac8eb5fec2 100644
--- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java
+++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java
@@ -11,6 +11,7 @@
import static java.util.stream.Collectors.toMap;
import com.google.auth.oauth2.GoogleCredentials;
+import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.auto.service.AutoService;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.contrib.gcp.auth.GoogleAuthException.Reason;
@@ -29,11 +30,17 @@
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.export.SpanExporter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
@@ -43,8 +50,9 @@
* integration.
*
*
This class is registered as a service provider using {@link AutoService} and is responsible
- * for customizing the OpenTelemetry configuration for GCP specific behavior. It retrieves Google
- * Application Default Credentials (ADC) and adds them as authorization headers to the configured
+ * for customizing the OpenTelemetry configuration for GCP specific behavior. It retrieves
+ * credentials (either explicit service account keys from configuration or falling back to
+ * Application Default Credentials (ADC)) and adds them as authorization headers to the configured
* {@link SpanExporter}. It also sets default properties and resource attributes for GCP
* integration.
*
@@ -57,6 +65,8 @@ public class GcpAuthAutoConfigurationCustomizerProvider
private static final Logger logger =
Logger.getLogger(GcpAuthAutoConfigurationCustomizerProvider.class.getName());
+ private static final Map credentialsCache =
+ Collections.synchronizedMap(new WeakHashMap<>());
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.",
@@ -75,8 +85,8 @@ public class GcpAuthAutoConfigurationCustomizerProvider
* Customizes the provided {@link AutoConfigurationCustomizer} such that authenticated exports to
* GCP Telemetry API are possible from the configured OTLP exporter.
*
- * This method attempts to retrieve Google Application Default Credentials (ADC) and performs
- * the following:
+ *
This method attempts to retrieve credentials (either from user-specified configuration or
+ * falling back to ADC) and performs the following:
*
*
* - Verifies whether the configured OTLP endpoint (base or signal specific) is a known GCP
@@ -99,22 +109,71 @@ public class GcpAuthAutoConfigurationCustomizerProvider
*/
@Override
public void customize(@Nonnull AutoConfigurationCustomizer autoConfiguration) {
- GoogleCredentials credentials;
- try {
- credentials = GoogleCredentials.getApplicationDefault();
- } catch (IOException e) {
- throw new GoogleAuthException(Reason.FAILED_ADC_RETRIEVAL, e);
- }
autoConfiguration
.addSpanExporterCustomizer(
(spanExporter, configProperties) ->
- customizeSpanExporter(spanExporter, credentials, configProperties))
+ customizeSpanExporter(
+ spanExporter, resolveCredentials(configProperties), configProperties))
.addMetricExporterCustomizer(
(metricExporter, configProperties) ->
- customizeMetricExporter(metricExporter, credentials, configProperties))
+ customizeMetricExporter(
+ metricExporter, resolveCredentials(configProperties), configProperties))
.addResourceCustomizer(
(resource, configProperties) ->
- customizeResource(resource, credentials, configProperties));
+ customizeResource(
+ resource, resolveCredentials(configProperties), configProperties));
+ }
+
+ private static GoogleCredentials resolveCredentials(ConfigProperties configProperties) {
+ synchronized (credentialsCache) {
+ GoogleCredentials cachedCredentials = credentialsCache.get(configProperties);
+ if (cachedCredentials != null) {
+ return cachedCredentials;
+ }
+
+ GoogleCredentials resolvedCredentials = loadCredentials(configProperties);
+ credentialsCache.put(configProperties, resolvedCredentials);
+ return resolvedCredentials;
+ }
+ }
+
+ private static GoogleCredentials loadCredentials(ConfigProperties configProperties) {
+ Optional credsPath =
+ ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_PATH.getConfiguredValueAsOptional(
+ configProperties);
+ if (credsPath.isPresent()) {
+ File file = new File(credsPath.get());
+ if (!file.exists()) {
+ throw new ConfigurationException("Credentials file not found: " + file.getName());
+ }
+ try (FileInputStream fis = new FileInputStream(file)) {
+ return ServiceAccountCredentials.fromStream(fis)
+ .createScoped(
+ Collections.singletonList("https://www.googleapis.com/auth/cloud-platform"));
+ } catch (IOException e) {
+ throw new GoogleAuthException(Reason.FAILED_CREDENTIAL_CREATION, e);
+ }
+ }
+
+ Optional credsJson =
+ ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_JSON.getConfiguredValueAsOptional(
+ configProperties);
+ if (credsJson.isPresent()) {
+ try (ByteArrayInputStream bais =
+ new ByteArrayInputStream(credsJson.get().getBytes(StandardCharsets.UTF_8))) {
+ return ServiceAccountCredentials.fromStream(bais)
+ .createScoped(
+ Collections.singletonList("https://www.googleapis.com/auth/cloud-platform"));
+ } catch (IOException e) {
+ throw new GoogleAuthException(Reason.FAILED_CREDENTIAL_CREATION, e);
+ }
+ }
+
+ try {
+ return GoogleCredentials.getApplicationDefault();
+ } catch (IOException e) {
+ throw new GoogleAuthException(Reason.FAILED_ADC_RETRIEVAL, e);
+ }
}
@Override
diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GoogleAuthException.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GoogleAuthException.java
index 2f6335f528..1303e10b79 100644
--- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GoogleAuthException.java
+++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GoogleAuthException.java
@@ -29,7 +29,9 @@ enum Reason {
/** Indicates a failure to retrieve Google Application Default Credentials. */
FAILED_ADC_RETRIEVAL("Unable to retrieve Google Application Default Credentials."),
/** Indicates a failure to retrieve Google Application Default Credentials. */
- FAILED_ADC_REFRESH("Unable to refresh Google Application Default Credentials.");
+ FAILED_ADC_REFRESH("Unable to refresh Google Application Default Credentials."),
+ /** Indicates a failure to create credentials from provided source. */
+ FAILED_CREDENTIAL_CREATION("Unable to create credentials from provided source.");
private final String message;
diff --git a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java
index 79b070737d..8486ae1597 100644
--- a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java
+++ b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java
@@ -18,6 +18,7 @@
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
+import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.common.AttributeKey;
@@ -51,7 +52,12 @@
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;
+import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.time.Duration;
import java.time.Instant;
import java.util.AbstractMap.SimpleEntry;
@@ -91,7 +97,7 @@ class GcpAuthAutoConfigurationCustomizerProviderTest {
private static final String DUMMY_GCP_QUOTA_PROJECT_ID = "my-gcp-quota-project-id";
private static final Random TEST_RANDOM = new Random();
- @Mock private GoogleCredentials mockedGoogleCredentials;
+ @Mock private ServiceAccountCredentials mockedGoogleCredentials;
@Captor private ArgumentCaptor>> traceHeaderSupplierCaptor;
@Captor private ArgumentCaptor>> metricHeaderSupplierCaptor;
@@ -243,6 +249,228 @@ void testTraceCustomizerOtlpGrpc() {
}
}
+ @Test
+ void testCredentialsLoadedFromFilePath() throws IOException {
+ File tempFile = File.createTempFile("gcp-creds", ".json");
+ tempFile.deleteOnExit();
+ try (Writer writer = Files.newBufferedWriter(tempFile.toPath(), StandardCharsets.UTF_8)) {
+ writer.write("{}");
+ }
+
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_ALL);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_PATH.getSystemProperty(),
+ tempFile.getAbsolutePath());
+
+ try {
+ prepareMockBehaviorForGoogleCredentials();
+ OtlpGrpcSpanExporter mockOtlpGrpcSpanExporter = Mockito.mock(OtlpGrpcSpanExporter.class);
+ OtlpGrpcSpanExporterBuilder spyOtlpGrpcSpanExporterBuilder =
+ Mockito.spy(OtlpGrpcSpanExporter.builder());
+ List exportedSpans = new ArrayList<>();
+ configureGrpcMockSpanExporter(
+ mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
+
+ try (MockedStatic serviceAccountCredentialsMockedStatic =
+ Mockito.mockStatic(ServiceAccountCredentials.class)) {
+ serviceAccountCredentialsMockedStatic
+ .when(() -> ServiceAccountCredentials.fromStream(any(InputStream.class)))
+ .thenReturn(mockedGoogleCredentials);
+
+ buildOpenTelemetrySdkWithExporter(mockOtlpGrpcSpanExporter);
+
+ serviceAccountCredentialsMockedStatic.verify(
+ () -> ServiceAccountCredentials.fromStream(any(InputStream.class)),
+ Mockito.atLeastOnce());
+ }
+ } finally {
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_PATH.getSystemProperty());
+ }
+ }
+
+ @Test
+ void testCredentialsLoadedFromJsonString() throws IOException {
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_ALL);
+ System.setProperty(ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_JSON.getSystemProperty(), "{}");
+
+ try {
+ prepareMockBehaviorForGoogleCredentials();
+ OtlpGrpcSpanExporter mockOtlpGrpcSpanExporter = Mockito.mock(OtlpGrpcSpanExporter.class);
+ OtlpGrpcSpanExporterBuilder spyOtlpGrpcSpanExporterBuilder =
+ Mockito.spy(OtlpGrpcSpanExporter.builder());
+ List exportedSpans = new ArrayList<>();
+ configureGrpcMockSpanExporter(
+ mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
+
+ try (MockedStatic serviceAccountCredentialsMockedStatic =
+ Mockito.mockStatic(ServiceAccountCredentials.class)) {
+ serviceAccountCredentialsMockedStatic
+ .when(() -> ServiceAccountCredentials.fromStream(any(InputStream.class)))
+ .thenReturn(mockedGoogleCredentials);
+
+ buildOpenTelemetrySdkWithExporter(mockOtlpGrpcSpanExporter);
+
+ serviceAccountCredentialsMockedStatic.verify(
+ () -> ServiceAccountCredentials.fromStream(any(InputStream.class)),
+ Mockito.atLeastOnce());
+ }
+ } finally {
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_JSON.getSystemProperty());
+ }
+ }
+
+ @Test
+ void testFallbackToApplicationDefaultCredentials() throws IOException {
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_ALL);
+
+ try {
+ prepareMockBehaviorForGoogleCredentials();
+ OtlpGrpcSpanExporter mockOtlpGrpcSpanExporter = Mockito.mock(OtlpGrpcSpanExporter.class);
+ OtlpGrpcSpanExporterBuilder spyOtlpGrpcSpanExporterBuilder =
+ Mockito.spy(OtlpGrpcSpanExporter.builder());
+ List exportedSpans = new ArrayList<>();
+ configureGrpcMockSpanExporter(
+ mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
+
+ try (MockedStatic googleCredentialsMockedStatic =
+ Mockito.mockStatic(GoogleCredentials.class);
+ MockedStatic serviceAccountCredentialsMockedStatic =
+ Mockito.mockStatic(ServiceAccountCredentials.class)) {
+
+ googleCredentialsMockedStatic
+ .when(GoogleCredentials::getApplicationDefault)
+ .thenReturn(mockedGoogleCredentials);
+
+ buildOpenTelemetrySdkWithExporter(mockOtlpGrpcSpanExporter);
+
+ googleCredentialsMockedStatic.verify(
+ GoogleCredentials::getApplicationDefault, Mockito.atLeastOnce());
+ serviceAccountCredentialsMockedStatic.verify(
+ () -> ServiceAccountCredentials.fromStream(any(InputStream.class)), Mockito.never());
+ }
+ } finally {
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty());
+ }
+ }
+
+ @Test
+ void testCredentialsPathTakesPrecedenceOverJson() throws IOException {
+ File tempFile = File.createTempFile("gcp-creds", ".json");
+ tempFile.deleteOnExit();
+ try (Writer writer = Files.newBufferedWriter(tempFile.toPath(), StandardCharsets.UTF_8)) {
+ writer.write("{}");
+ }
+
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_ALL);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_PATH.getSystemProperty(),
+ tempFile.getAbsolutePath());
+ System.setProperty(ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_JSON.getSystemProperty(), "{}");
+
+ try {
+ prepareMockBehaviorForGoogleCredentials();
+ OtlpGrpcSpanExporter mockOtlpGrpcSpanExporter = Mockito.mock(OtlpGrpcSpanExporter.class);
+ OtlpGrpcSpanExporterBuilder spyOtlpGrpcSpanExporterBuilder =
+ Mockito.spy(OtlpGrpcSpanExporter.builder());
+ List exportedSpans = new ArrayList<>();
+ configureGrpcMockSpanExporter(
+ mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
+
+ try (MockedStatic googleCredentialsMockedStatic =
+ Mockito.mockStatic(GoogleCredentials.class);
+ MockedStatic serviceAccountCredentialsMockedStatic =
+ Mockito.mockStatic(ServiceAccountCredentials.class)) {
+
+ serviceAccountCredentialsMockedStatic
+ .when(() -> ServiceAccountCredentials.fromStream(any(InputStream.class)))
+ .thenReturn(mockedGoogleCredentials);
+
+ buildOpenTelemetrySdkWithExporter(mockOtlpGrpcSpanExporter);
+
+ serviceAccountCredentialsMockedStatic.verify(
+ () -> ServiceAccountCredentials.fromStream(any(InputStream.class)),
+ Mockito.atLeastOnce());
+ googleCredentialsMockedStatic.verify(
+ GoogleCredentials::getApplicationDefault, Mockito.never());
+ }
+ } finally {
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_PATH.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_JSON.getSystemProperty());
+ }
+ }
+
+ @Test
+ void testCredentialsFileNodeFoundThrowsConfigurationException() {
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_ALL);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_PATH.getSystemProperty(),
+ "/non/existent/path.json");
+
+ try {
+ OtlpGrpcSpanExporter mockOtlpGrpcSpanExporter = Mockito.mock(OtlpGrpcSpanExporter.class);
+
+ assertThatThrownBy(() -> buildOpenTelemetrySdkWithExporter(mockOtlpGrpcSpanExporter))
+ .isInstanceOf(ConfigurationException.class)
+ .hasMessageContaining("Credentials file not found");
+ } finally {
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_PATH.getSystemProperty());
+ }
+ }
+
+ @Test
+ void testMalformedCredentialsJsonThrowsGoogleAuthException() {
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_ALL);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_JSON.getSystemProperty(), "malformed_json");
+
+ try {
+ OtlpGrpcSpanExporter mockOtlpGrpcSpanExporter = Mockito.mock(OtlpGrpcSpanExporter.class);
+
+ try (MockedStatic serviceAccountCredentialsMockedStatic =
+ Mockito.mockStatic(ServiceAccountCredentials.class)) {
+ serviceAccountCredentialsMockedStatic
+ .when(() -> ServiceAccountCredentials.fromStream(any(InputStream.class)))
+ .thenThrow(new IOException("Malformed JSON"));
+
+ assertThatThrownBy(() -> buildOpenTelemetrySdkWithExporter(mockOtlpGrpcSpanExporter))
+ .isInstanceOf(GoogleAuthException.class)
+ .hasMessageContaining(
+ GoogleAuthException.Reason.FAILED_CREDENTIAL_CREATION.getMessage());
+ }
+ } finally {
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty());
+ System.clearProperty(ConfigurableOption.GOOGLE_CLOUD_CREDENTIALS_JSON.getSystemProperty());
+ }
+ }
+
// TODO: Use parameterized test for testing metrics customizer for http & grpc.
@Test
void testMetricCustomizerOtlpHttp() {