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 5f4a627e1..639207909 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 @@ -5,6 +5,7 @@ package io.opentelemetry.contrib.gcp.auth; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import java.util.Locale; import java.util.Optional; @@ -14,7 +15,7 @@ * An enum representing configurable options for a GCP Authentication Extension. Each option has a * user-readable name and can be configured using environment variables or system properties. */ -public enum ConfigurableOption { +enum ConfigurableOption { /** * Represents the Google Cloud Project ID option. Can be configured using the environment variable * `GOOGLE_CLOUD_PROJECT` or the system property `google.cloud.project`. @@ -50,7 +51,7 @@ public 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 Auth Extension"); + GOOGLE_OTEL_AUTH_TARGET_SIGNALS("Target Signals for Google Authentication Extension"); private final String userReadableName; private final String environmentVariableName; @@ -60,7 +61,7 @@ public enum ConfigurableOption { this.userReadableName = userReadableName; this.environmentVariableName = this.name(); this.systemPropertyName = - this.environmentVariableName.toLowerCase(Locale.ENGLISH).replace('_', '.'); + this.environmentVariableName.toLowerCase(Locale.ROOT).replace('_', '.'); } /** @@ -81,6 +82,15 @@ String getSystemProperty() { return this.systemPropertyName; } + /** + * Returns the user readable name associated with this option. + * + * @return the user readable name (e.g., "Google Cloud Quota Project ID") + */ + String getUserReadableName() { + return this.userReadableName; + } + /** * Retrieves the configured value for this option. This method checks the environment variable * first and then the system property. @@ -89,14 +99,10 @@ String getSystemProperty() { * @throws ConfigurationException if neither the environment variable nor the system property is * set. */ - String getConfiguredValue() { - String envVar = System.getenv(this.getEnvironmentVariable()); - String sysProp = System.getProperty(this.getSystemProperty()); - - if (envVar != null && !envVar.isEmpty()) { - return envVar; - } else if (sysProp != null && !sysProp.isEmpty()) { - return sysProp; + String getConfiguredValue(ConfigProperties configProperties) { + String configuredValue = configProperties.getString(this.getSystemProperty()); + if (configuredValue != null && !configuredValue.isEmpty()) { + return configuredValue; } else { throw new ConfigurationException( String.format( @@ -115,9 +121,10 @@ String getConfiguredValue() { * @return The configured value for the option, obtained from the environment variable, system * property, or the fallback function, in that order of precedence. */ - String getConfiguredValueWithFallback(Supplier fallback) { + String getConfiguredValueWithFallback( + ConfigProperties configProperties, Supplier fallback) { try { - return this.getConfiguredValue(); + return this.getConfiguredValue(configProperties); } catch (ConfigurationException e) { return fallback.get(); } @@ -131,9 +138,9 @@ String getConfiguredValueWithFallback(Supplier fallback) { * @return The configured value for the option, if set, obtained from the environment variable, * system property, or empty {@link Optional}, in that order of precedence. */ - Optional getConfiguredValueAsOptional() { + Optional getConfiguredValueAsOptional(ConfigProperties configProperties) { try { - return Optional.of(this.getConfiguredValue()); + return Optional.of(this.getConfiguredValue(configProperties)); } catch (ConfigurationException e) { return Optional.empty(); } 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 d6c68e54f..1de583029 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 @@ -30,6 +30,8 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import javax.annotation.Nonnull; @@ -50,6 +52,15 @@ public class GcpAuthAutoConfigurationCustomizerProvider implements AutoConfigurationCustomizerProvider { + private static final Logger logger = + 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"; @@ -93,10 +104,11 @@ public void customize(@Nonnull AutoConfigurationCustomizer autoConfiguration) { } autoConfiguration .addSpanExporterCustomizer( - (spanExporter, configProperties) -> customizeSpanExporter(spanExporter, credentials)) + (spanExporter, configProperties) -> + customizeSpanExporter(spanExporter, credentials, configProperties)) .addMetricExporterCustomizer( (metricExporter, configProperties) -> - customizeMetricExporter(metricExporter, credentials)) + customizeMetricExporter(metricExporter, credentials, configProperties)) .addResourceCustomizer(GcpAuthAutoConfigurationCustomizerProvider::customizeResource); } @@ -106,26 +118,38 @@ public int order() { } private static SpanExporter customizeSpanExporter( - SpanExporter exporter, GoogleCredentials credentials) { - if (isSignalTargeted(SIGNAL_TYPE_TRACES)) { - return addAuthorizationHeaders(exporter, credentials); + SpanExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { + if (isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { + return addAuthorizationHeaders(exporter, credentials, configProperties); + } else { + String[] params = {SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION}; + logger.log( + Level.WARNING, + "GCP Authentication Extension is not configured for signal type: {0}. {1}", + params); } return exporter; } private static MetricExporter customizeMetricExporter( - MetricExporter exporter, GoogleCredentials credentials) { - if (isSignalTargeted(SIGNAL_TYPE_METRICS)) { - return addAuthorizationHeaders(exporter, credentials); + MetricExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { + if (isSignalTargeted(SIGNAL_TYPE_METRICS, configProperties)) { + return addAuthorizationHeaders(exporter, credentials, configProperties); + } else { + String[] params = {SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_FIX_SUGGESTION}; + logger.log( + Level.WARNING, + "GCP Authentication Extension is not configured for signal type: {0}. {1}", + params); } return exporter; } // Checks if the auth extension is configured to target the passed signal for authentication. - private static boolean isSignalTargeted(String checkSignal) { + private static boolean isSignalTargeted(String checkSignal, ConfigProperties configProperties) { String userSpecifiedTargetedSignals = ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getConfiguredValueWithFallback( - () -> SIGNAL_TYPE_ALL); + configProperties, () -> SIGNAL_TYPE_ALL); return Arrays.stream(userSpecifiedTargetedSignals.split(",")) .map(String::trim) .anyMatch( @@ -136,16 +160,16 @@ private static boolean isSignalTargeted(String checkSignal) { // Adds authorization headers to the calls made by the OtlpGrpcSpanExporter and // OtlpHttpSpanExporter. private static SpanExporter addAuthorizationHeaders( - SpanExporter exporter, GoogleCredentials credentials) { + SpanExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { if (exporter instanceof OtlpHttpSpanExporter) { OtlpHttpSpanExporterBuilder builder = ((OtlpHttpSpanExporter) exporter) - .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials)); + .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials, configProperties)); return builder.build(); } else if (exporter instanceof OtlpGrpcSpanExporter) { OtlpGrpcSpanExporterBuilder builder = ((OtlpGrpcSpanExporter) exporter) - .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials)); + .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials, configProperties)); return builder.build(); } return exporter; @@ -154,22 +178,23 @@ private static SpanExporter addAuthorizationHeaders( // Adds authorization headers to the calls made by the OtlpGrpcMetricExporter and // OtlpHttpMetricExporter. private static MetricExporter addAuthorizationHeaders( - MetricExporter exporter, GoogleCredentials credentials) { + MetricExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { if (exporter instanceof OtlpHttpMetricExporter) { OtlpHttpMetricExporterBuilder builder = ((OtlpHttpMetricExporter) exporter) - .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials)); + .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials, configProperties)); return builder.build(); } else if (exporter instanceof OtlpGrpcMetricExporter) { OtlpGrpcMetricExporterBuilder builder = ((OtlpGrpcMetricExporter) exporter) - .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials)); + .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials, configProperties)); return builder.build(); } return exporter; } - private static Map getRequiredHeaderMap(GoogleCredentials credentials) { + private static Map getRequiredHeaderMap( + GoogleCredentials credentials, ConfigProperties configProperties) { Map> gcpHeaders; try { // this also refreshes the credentials, if required @@ -192,7 +217,8 @@ private static Map getRequiredHeaderMap(GoogleCredentials creden // system properties. if (!flattenedHeaders.containsKey(QUOTA_USER_PROJECT_HEADER)) { Optional maybeConfiguredQuotaProjectId = - ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValueAsOptional(); + ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValueAsOptional( + configProperties); maybeConfiguredQuotaProjectId.ifPresent( configuredQuotaProjectId -> flattenedHeaders.put(QUOTA_USER_PROJECT_HEADER, configuredQuotaProjectId)); @@ -202,7 +228,8 @@ private static Map getRequiredHeaderMap(GoogleCredentials creden // Updates the current resource with the attributes required for ingesting OTLP data on GCP. private static Resource customizeResource(Resource resource, ConfigProperties configProperties) { - String gcpProjectId = ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue(); + String gcpProjectId = + ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue(configProperties); Resource res = Resource.create( Attributes.of(AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY), gcpProjectId)); 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 de96dc382..6cc1797f0 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 @@ -941,7 +941,6 @@ private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter( spanExporter, OtlpHttpMetricExporter.getDefault(), customOTelProperties); } - @SuppressWarnings("UnusedMethod") private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(MetricExporter metricExporter) { return buildOpenTelemetrySdkWithExporter( OtlpHttpSpanExporter.getDefault(), metricExporter, defaultOtelPropertiesMetricExporter);