Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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`.
Expand Down Expand Up @@ -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;
Expand All @@ -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('_', '.');
}

/**
Expand All @@ -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.
Expand All @@ -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(
Expand All @@ -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<String> fallback) {
String getConfiguredValueWithFallback(
ConfigProperties configProperties, Supplier<String> fallback) {
try {
return this.getConfiguredValue();
return this.getConfiguredValue(configProperties);
} catch (ConfigurationException e) {
return fallback.get();
}
Expand All @@ -131,9 +138,9 @@ String getConfiguredValueWithFallback(Supplier<String> 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<String> getConfiguredValueAsOptional() {
Optional<String> getConfiguredValueAsOptional(ConfigProperties configProperties) {
try {
return Optional.of(this.getConfiguredValue());
return Optional.of(this.getConfiguredValue(configProperties));
} catch (ConfigurationException e) {
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -50,6 +52,18 @@
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());
private static final String SIGNAL_TARGET_WARNING_MSG =
"GCP Authentication Extension is not configured for signal type: %s. "
+ SIGNAL_TARGET_WARNING_FIX_SUGGESTION;

static final String QUOTA_USER_PROJECT_HEADER = "x-goog-user-project";
static final String GCP_USER_PROJECT_ID_KEY = "gcp.project_id";

Expand Down Expand Up @@ -93,10 +107,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);
}

Expand All @@ -106,26 +121,30 @@ 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 {
logger.log(Level.WARNING, String.format(SIGNAL_TARGET_WARNING_MSG, SIGNAL_TYPE_TRACES));
}
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 {
logger.log(Level.WARNING, String.format(SIGNAL_TARGET_WARNING_MSG, SIGNAL_TYPE_METRICS));
}
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(
Expand All @@ -136,16 +155,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;
Expand All @@ -154,22 +173,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<String, String> getRequiredHeaderMap(GoogleCredentials credentials) {
private static Map<String, String> getRequiredHeaderMap(
GoogleCredentials credentials, ConfigProperties configProperties) {
Map<String, List<String>> gcpHeaders;
try {
// this also refreshes the credentials, if required
Expand All @@ -192,7 +212,8 @@ private static Map<String, String> getRequiredHeaderMap(GoogleCredentials creden
// system properties.
if (!flattenedHeaders.containsKey(QUOTA_USER_PROJECT_HEADER)) {
Optional<String> maybeConfiguredQuotaProjectId =
ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValueAsOptional();
ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValueAsOptional(
configProperties);
maybeConfiguredQuotaProjectId.ifPresent(
configuredQuotaProjectId ->
flattenedHeaders.put(QUOTA_USER_PROJECT_HEADER, configuredQuotaProjectId));
Expand All @@ -202,7 +223,8 @@ private static Map<String, String> 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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,6 @@ private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(
spanExporter, OtlpHttpMetricExporter.getDefault(), customOTelProperties);
}

@SuppressWarnings("UnusedMethod")
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(MetricExporter metricExporter) {
return buildOpenTelemetrySdkWithExporter(
OtlpHttpSpanExporter.getDefault(), metricExporter, defaultOtelPropertiesMetricExporter);
Expand Down
Loading