From 51cd51760cc311440e39e397f730042d5a45604a Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 11 Jul 2025 12:06:05 +0200 Subject: [PATCH 01/41] gcp auth --- gcp-auth-extension/build.gradle.kts | 1 + ...thAutoConfigurationCustomizerProvider.java | 19 +- .../gcp/auth/GcpAuthCustomizerProvider.java | 191 ++++++++++++++++++ 3 files changed, 204 insertions(+), 7 deletions(-) create mode 100644 gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java diff --git a/gcp-auth-extension/build.gradle.kts b/gcp-auth-extension/build.gradle.kts index f81e5e521..d606782b0 100644 --- a/gcp-auth-extension/build.gradle.kts +++ b/gcp-auth-extension/build.gradle.kts @@ -21,6 +21,7 @@ dependencies { compileOnly("com.google.auto.service:auto-service-annotations") compileOnly("io.opentelemetry:opentelemetry-api") compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") compileOnly("io.opentelemetry:opentelemetry-exporter-otlp") // Only dependencies added to `implementation` configuration will be picked up by Shadow plugin 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 1de583029..f3ea7b206 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 @@ -96,12 +96,7 @@ 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); - } + GoogleCredentials credentials = getCredentials(); autoConfiguration .addSpanExporterCustomizer( (spanExporter, configProperties) -> @@ -112,6 +107,16 @@ public void customize(@Nonnull AutoConfigurationCustomizer autoConfiguration) { .addResourceCustomizer(GcpAuthAutoConfigurationCustomizerProvider::customizeResource); } + static GoogleCredentials getCredentials() { + GoogleCredentials credentials; + try { + credentials = GoogleCredentials.getApplicationDefault(); + } catch (IOException e) { + throw new GoogleAuthException(Reason.FAILED_ADC_RETRIEVAL, e); + } + return credentials; + } + @Override public int order() { return Integer.MAX_VALUE - 1; @@ -193,7 +198,7 @@ private static MetricExporter addAuthorizationHeaders( return exporter; } - private static Map getRequiredHeaderMap( + static Map getRequiredHeaderMap( GoogleCredentials credentials, ConfigProperties configProperties) { Map> gcpHeaders; try { diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java new file mode 100644 index 000000000..a06008562 --- /dev/null +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -0,0 +1,191 @@ +package io.opentelemetry.contrib.gcp.auth; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.auto.service.AutoService; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpGrpcExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpGrpcMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleLogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleSpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@AutoService(DeclarativeConfigurationCustomizerProvider.class) +public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { + + @Override + public void customize(DeclarativeConfigurationCustomizer customizer) { + customizer.addModelCustomizer( + model -> { + GoogleCredentials credentials = GcpAuthAutoConfigurationCustomizerProvider.getCredentials(); + // todo pass config bridge + Map headerMap = GcpAuthAutoConfigurationCustomizerProvider.getRequiredHeaderMap( + credentials, null); + customizeMeter(model, headerMap); + // todo are loggers supported now (not covered in old variant)? + customizeLogger(model, headerMap); + customizeTracer(model, headerMap); + + return model; + }); + } + + private void customizeMeter(OpenTelemetryConfigurationModel model, + Map headerMap) { + MeterProviderModel meterProvider = model.getMeterProvider(); + if (meterProvider == null) { + return; + } + + for (MetricReaderModel reader : meterProvider.getReaders()) { + if (reader.getPeriodic() != null) { + addAuth(meterModelHeaders(reader.getPeriodic().getExporter()), + headerMap); + } + } + } + + private List> meterModelHeaders( + PushMetricExporterModel exporter) { + ArrayList> list = new ArrayList<>(); + if (exporter == null) { + return list; + } + OtlpGrpcMetricExporterModel grpc = exporter.getOtlpGrpc(); + if (grpc != null) { + list.add(grpc.getHeaders()); + } + OtlpHttpMetricExporterModel http = exporter.getOtlpHttp(); + if (http != null) { + list.add(http.getHeaders()); + } + return list; + } + + private void customizeLogger(OpenTelemetryConfigurationModel model, + Map headerMap) { + LoggerProviderModel loggerProvider = model.getLoggerProvider(); + if (loggerProvider == null) { + return; + } + for (LogRecordProcessorModel processor : loggerProvider.getProcessors()) { + BatchLogRecordProcessorModel batch = processor.getBatch(); + if (batch != null) { + addAuth(logRecordModelHeaders(batch.getExporter()), + headerMap); + } + SimpleLogRecordProcessorModel simple = processor.getSimple(); + if (simple != null) { + addAuth(logRecordModelHeaders(simple.getExporter()), + headerMap); + } + } + } + + private List> logRecordModelHeaders( + LogRecordExporterModel exporter) { + ArrayList> list = new ArrayList<>(); + + if (exporter == null) { + return list; + } + OtlpGrpcExporterModel grpc = exporter.getOtlpGrpc(); + if (grpc != null) { + list.add(grpc.getHeaders()); + } + OtlpHttpExporterModel http = exporter.getOtlpHttp(); + if (http != null) { + list.add(http.getHeaders()); + } + return list; + } + + private void customizeTracer(OpenTelemetryConfigurationModel model, + Map headerMap) { + TracerProviderModel tracerProvider = model.getTracerProvider(); + if (tracerProvider == null) { + return; + } + + // todo here we would want a simplified version of the declarative config bridge + // https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/DeclarativeConfigPropertiesBridge.java +// googleNode(model) + +// if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { + // todo +// 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; +// } + + for (SpanProcessorModel processor : tracerProvider.getProcessors()) { + BatchSpanProcessorModel batch = processor.getBatch(); + if (batch != null) { + addAuth(spanExporterModelHeaders(batch.getExporter()), + headerMap); + } + SimpleSpanProcessorModel simple = processor.getSimple(); + if (simple != null) { + addAuth(spanExporterModelHeaders(simple.getExporter()), + headerMap); + } + } + } + + private void googleNode(OpenTelemetryConfigurationModel model) { + // todo use declarative config bridge + } + + private List> spanExporterModelHeaders( + SpanExporterModel exporter) { + ArrayList> list = new ArrayList<>(); + + if (exporter == null) { + return list; + } + OtlpGrpcExporterModel grpc = exporter.getOtlpGrpc(); + if (grpc != null) { + list.add(grpc.getHeaders()); + } + OtlpHttpExporterModel http = exporter.getOtlpHttp(); + if (http != null) { + list.add(http.getHeaders()); + } + return list; + } + + private void addAuth( + List> headerConsumers, Map headerMap) { + headerConsumers.forEach( + headers -> addHeaders(headers, headerMap)); + } + + private void addHeaders(List headers, Map add) { + add.forEach( + (key, value) -> { + if (headers.stream().noneMatch(header -> key.equals(header.getName()))) { + headers.add(new NameStringValuePairModel().withName(key).withValue(value)); + } + }); + } +} From 4a6bda9384551d3718d698c31ee1002ccfee85db Mon Sep 17 00:00:00 2001 From: otelbot <197425009+otelbot@users.noreply.github.com> Date: Fri, 11 Jul 2025 10:07:55 +0000 Subject: [PATCH 02/41] ./gradlew spotlessApply --- ...thAutoConfigurationCustomizerProvider.java | 2 +- .../gcp/auth/GcpAuthCustomizerProvider.java | 67 +++++++++---------- 2 files changed, 34 insertions(+), 35 deletions(-) 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 f3ea7b206..b06359c38 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 @@ -107,7 +107,7 @@ public void customize(@Nonnull AutoConfigurationCustomizer autoConfiguration) { .addResourceCustomizer(GcpAuthAutoConfigurationCustomizerProvider::customizeResource); } - static GoogleCredentials getCredentials() { + static GoogleCredentials getCredentials() { GoogleCredentials credentials; try { credentials = GoogleCredentials.getApplicationDefault(); diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java index a06008562..e2512aab6 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.contrib.gcp.auth; import com.google.auth.oauth2.GoogleCredentials; @@ -34,10 +39,11 @@ public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustom public void customize(DeclarativeConfigurationCustomizer customizer) { customizer.addModelCustomizer( model -> { - GoogleCredentials credentials = GcpAuthAutoConfigurationCustomizerProvider.getCredentials(); + GoogleCredentials credentials = + GcpAuthAutoConfigurationCustomizerProvider.getCredentials(); // todo pass config bridge - Map headerMap = GcpAuthAutoConfigurationCustomizerProvider.getRequiredHeaderMap( - credentials, null); + Map headerMap = + GcpAuthAutoConfigurationCustomizerProvider.getRequiredHeaderMap(credentials, null); customizeMeter(model, headerMap); // todo are loggers supported now (not covered in old variant)? customizeLogger(model, headerMap); @@ -47,8 +53,8 @@ public void customize(DeclarativeConfigurationCustomizer customizer) { }); } - private void customizeMeter(OpenTelemetryConfigurationModel model, - Map headerMap) { + private void customizeMeter( + OpenTelemetryConfigurationModel model, Map headerMap) { MeterProviderModel meterProvider = model.getMeterProvider(); if (meterProvider == null) { return; @@ -56,14 +62,12 @@ private void customizeMeter(OpenTelemetryConfigurationModel model, for (MetricReaderModel reader : meterProvider.getReaders()) { if (reader.getPeriodic() != null) { - addAuth(meterModelHeaders(reader.getPeriodic().getExporter()), - headerMap); + addAuth(meterModelHeaders(reader.getPeriodic().getExporter()), headerMap); } } } - private List> meterModelHeaders( - PushMetricExporterModel exporter) { + private List> meterModelHeaders(PushMetricExporterModel exporter) { ArrayList> list = new ArrayList<>(); if (exporter == null) { return list; @@ -79,8 +83,8 @@ private List> meterModelHeaders( return list; } - private void customizeLogger(OpenTelemetryConfigurationModel model, - Map headerMap) { + private void customizeLogger( + OpenTelemetryConfigurationModel model, Map headerMap) { LoggerProviderModel loggerProvider = model.getLoggerProvider(); if (loggerProvider == null) { return; @@ -88,13 +92,11 @@ private void customizeLogger(OpenTelemetryConfigurationModel model, for (LogRecordProcessorModel processor : loggerProvider.getProcessors()) { BatchLogRecordProcessorModel batch = processor.getBatch(); if (batch != null) { - addAuth(logRecordModelHeaders(batch.getExporter()), - headerMap); + addAuth(logRecordModelHeaders(batch.getExporter()), headerMap); } SimpleLogRecordProcessorModel simple = processor.getSimple(); if (simple != null) { - addAuth(logRecordModelHeaders(simple.getExporter()), - headerMap); + addAuth(logRecordModelHeaders(simple.getExporter()), headerMap); } } } @@ -117,8 +119,8 @@ private List> logRecordModelHeaders( return list; } - private void customizeTracer(OpenTelemetryConfigurationModel model, - Map headerMap) { + private void customizeTracer( + OpenTelemetryConfigurationModel model, Map headerMap) { TracerProviderModel tracerProvider = model.getTracerProvider(); if (tracerProvider == null) { return; @@ -126,28 +128,26 @@ private void customizeTracer(OpenTelemetryConfigurationModel model, // todo here we would want a simplified version of the declarative config bridge // https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/DeclarativeConfigPropertiesBridge.java -// googleNode(model) - -// if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { - // todo -// 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; -// } + // googleNode(model) + + // if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { + // todo + // 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; + // } for (SpanProcessorModel processor : tracerProvider.getProcessors()) { BatchSpanProcessorModel batch = processor.getBatch(); if (batch != null) { - addAuth(spanExporterModelHeaders(batch.getExporter()), - headerMap); + addAuth(spanExporterModelHeaders(batch.getExporter()), headerMap); } SimpleSpanProcessorModel simple = processor.getSimple(); if (simple != null) { - addAuth(spanExporterModelHeaders(simple.getExporter()), - headerMap); + addAuth(spanExporterModelHeaders(simple.getExporter()), headerMap); } } } @@ -176,8 +176,7 @@ private List> spanExporterModelHeaders( private void addAuth( List> headerConsumers, Map headerMap) { - headerConsumers.forEach( - headers -> addHeaders(headers, headerMap)); + headerConsumers.forEach(headers -> addHeaders(headers, headerMap)); } private void addHeaders(List headers, Map add) { From d6f03ab712c52fbd7310bc57964d737d3ae67b59 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 17:25:05 +0200 Subject: [PATCH 03/41] copy declarative config bridge from instrumentation --- declarative-config-bridge/build.gradle.kts | 17 ++ .../autoconfigure/ConfigPropertiesUtil.java | 55 ++++++ .../DeclarativeConfigPropertiesBridge.java | 158 ++++++++++++++++++ .../ConfigPropertiesUtilTest.java | 87 ++++++++++ ...DeclarativeConfigPropertiesBridgeTest.java | 137 +++++++++++++++ settings.gradle.kts | 1 + 6 files changed, 455 insertions(+) create mode 100644 declarative-config-bridge/build.gradle.kts create mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java create mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java create mode 100644 declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java create mode 100644 declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java diff --git a/declarative-config-bridge/build.gradle.kts b/declarative-config-bridge/build.gradle.kts new file mode 100644 index 000000000..66fb4658b --- /dev/null +++ b/declarative-config-bridge/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + id("otel.java-conventions") + id("otel.publish-conventions") +} + +description = "OpenTelemetry extension that provides a bridge for declarative configuration." +otelJava.moduleName.set("io.opentelemetry.contrib.sdk.declarative.config.bridge") + +dependencies { + // We use `compileOnly` dependency because during runtime all necessary classes are provided by + // javaagent itself. + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") + + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") +} diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java new file mode 100644 index 000000000..af6cc6397 --- /dev/null +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sdk.autoconfigure; + +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; + +public class ConfigPropertiesUtil { + private ConfigPropertiesUtil() { + } + + /** + * Resolve {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. + */ + public static ConfigProperties resolveConfigProperties( + AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { + ConfigProperties sdkConfigProperties = + AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); + if (sdkConfigProperties != null) { + return sdkConfigProperties; + } + ConfigProvider configProvider = + AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); + if (configProvider != null) { + DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); + + if (instrumentationConfig == null) { + instrumentationConfig = DeclarativeConfigProperties.empty(); + } + + return new DeclarativeConfigPropertiesBridge(instrumentationConfig); + } + // Should never happen + throw new IllegalStateException( + "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); + } + + public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel model) { + SdkConfigProvider configProvider = SdkConfigProvider.create(model); + DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); + if (instrumentationConfig == null) { + instrumentationConfig = DeclarativeConfigProperties.empty(); + } + + return new DeclarativeConfigPropertiesBridge(instrumentationConfig); + } +} diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java new file mode 100644 index 000000000..0721e4a69 --- /dev/null +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -0,0 +1,158 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sdk.autoconfigure; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; + +import javax.annotation.Nullable; +import java.time.Duration; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; + +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; + +/** + * A {@link ConfigProperties} which resolves properties based on {@link + * DeclarativeConfigProperties}. + * + *

Only properties starting with "otel.instrumentation." are resolved. Others return null (or + * default value if provided). + * + *

To resolve: + * + *

    + *
  • "otel.instrumentation" refers to the ".instrumentation.java" node + *
  • The portion of the property after "otel.instrumentation." is split into segments based on + * ".". + *
  • For each N-1 segment, we walk down the tree to find the relevant leaf {@link + * DeclarativeConfigProperties}. + *
  • We extract the property from the resolved {@link DeclarativeConfigProperties} using the + * last segment as the property key. + *
+ * + *

For example, given the following YAML, asking for {@code + * ConfigProperties#getString("otel.instrumentation.common.string_key")} yields "value": + * + *

+ *   instrumentation:
+ *     java:
+ *       common:
+ *         string_key: value
+ * 
+ */ +final class DeclarativeConfigPropertiesBridge implements ConfigProperties { + + private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; + + // The node at .instrumentation.java + private final DeclarativeConfigProperties instrumentationJavaNode; + + DeclarativeConfigPropertiesBridge(DeclarativeConfigProperties instrumentationNode) { + instrumentationJavaNode = instrumentationNode.getStructured("java", empty()); + } + + @Nullable + @Override + public String getString(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getString); + } + + @Nullable + @Override + public Boolean getBoolean(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getBoolean); + } + + @Nullable + @Override + public Integer getInt(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getInt); + } + + @Nullable + @Override + public Long getLong(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + } + + @Nullable + @Override + public Double getDouble(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getDouble); + } + + @Nullable + @Override + public Duration getDuration(String propertyName) { + Long millis = getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + if (millis == null) { + return null; + } + return Duration.ofMillis(millis); + } + + @Override + public List getList(String propertyName) { + List propertyValue = + getPropertyValue( + propertyName, + (properties, lastPart) -> properties.getScalarList(lastPart, String.class)); + return propertyValue == null ? Collections.emptyList() : propertyValue; + } + + @Override + public Map getMap(String propertyName) { + DeclarativeConfigProperties propertyValue = + getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); + if (propertyValue == null) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + propertyValue + .getPropertyKeys() + .forEach( + key -> { + String value = propertyValue.getString(key); + if (value == null) { + return; + } + result.put(key, value); + }); + return Collections.unmodifiableMap(result); + } + + @Nullable + private T getPropertyValue( + String property, BiFunction extractor) { + if (instrumentationJavaNode == null) { + return null; + } + + if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { + property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); + } + // Split the remainder of the property on "." + String[] segments = property.split("\\."); + if (segments.length == 0) { + return null; + } + + // Extract the value by walking to the N-1 entry + DeclarativeConfigProperties target = instrumentationJavaNode; + if (segments.length > 1) { + for (int i = 0; i < segments.length - 1; i++) { + target = target.getStructured(segments[i], empty()); + } + } + String lastPart = segments[segments.length - 1]; + + return extractor.apply(target, lastPart); + } +} diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java new file mode 100644 index 000000000..8d88e9783 --- /dev/null +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java @@ -0,0 +1,87 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sdk.autoconfigure; + + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +@SuppressWarnings("DoNotMockAutoValue") +class ConfigPropertiesUtilTest { + @Test + void shouldUseConfigPropertiesForAutoConfiguration() { + ConfigProperties configPropertiesMock = mock(ConfigProperties.class); + AutoConfiguredOpenTelemetrySdk sdkMock = mock(AutoConfiguredOpenTelemetrySdk.class); + try (MockedStatic autoConfigureUtilMock = + Mockito.mockStatic(AutoConfigureUtil.class)) { + autoConfigureUtilMock + .when(() -> AutoConfigureUtil.getConfig(sdkMock)) + .thenReturn(configPropertiesMock); + + ConfigProperties configProperties = ConfigPropertiesUtil.resolveConfigProperties(sdkMock); + + assertThat(configProperties).isSameAs(configPropertiesMock); + } + } + + @Test + void shouldUseConfigProviderForDeclarativeConfiguration() { + String propertyName = "testProperty"; + String expectedValue = "the value"; + DeclarativeConfigProperties javaNodeMock = mock(DeclarativeConfigProperties.class); + when(javaNodeMock.getString(propertyName)).thenReturn(expectedValue); + + DeclarativeConfigProperties instrumentationConfigMock = mock(DeclarativeConfigProperties.class); + when(instrumentationConfigMock.getStructured(eq("java"), any())).thenReturn(javaNodeMock); + + ConfigProvider configProviderMock = mock(ConfigProvider.class); + when(configProviderMock.getInstrumentationConfig()).thenReturn(instrumentationConfigMock); + + AutoConfiguredOpenTelemetrySdk sdkMock = mock(AutoConfiguredOpenTelemetrySdk.class); + + try (MockedStatic autoConfigureUtilMock = + Mockito.mockStatic(AutoConfigureUtil.class)) { + autoConfigureUtilMock.when(() -> AutoConfigureUtil.getConfig(sdkMock)).thenReturn(null); + autoConfigureUtilMock + .when(() -> AutoConfigureUtil.getConfigProvider(sdkMock)) + .thenReturn(configProviderMock); + + ConfigProperties configProperties = ConfigPropertiesUtil.resolveConfigProperties(sdkMock); + + assertThat(configProperties.getString(propertyName)).isEqualTo(expectedValue); + } + } + + @Test + void shouldUseConfigProviderForDeclarativeConfiguration_noInstrumentationConfig() { + AutoConfiguredOpenTelemetrySdk sdkMock = mock(AutoConfiguredOpenTelemetrySdk.class); + ConfigProvider configProviderMock = mock(ConfigProvider.class); + when(configProviderMock.getInstrumentationConfig()).thenReturn(null); + + try (MockedStatic autoConfigureUtilMock = + Mockito.mockStatic(AutoConfigureUtil.class)) { + autoConfigureUtilMock.when(() -> AutoConfigureUtil.getConfig(sdkMock)).thenReturn(null); + autoConfigureUtilMock + .when(() -> AutoConfigureUtil.getConfigProvider(sdkMock)) + .thenReturn(configProviderMock); + + ConfigProperties configProperties = ConfigPropertiesUtil.resolveConfigProperties(sdkMock); + + assertThat(configProperties.getString("testProperty")).isEqualTo(null); + } + } +} diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java new file mode 100644 index 000000000..5bff96e16 --- /dev/null +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java @@ -0,0 +1,137 @@ +package io.opentelemetry.contrib.sdk.autoconfigure;/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class DeclarativeConfigPropertiesBridgeTest { + + private static final String YAML = + "file_format: 0.4\n" + + "instrumentation/development:\n" + + " java:\n" + + " common:\n" + + " default-enabled: true\n" + + " runtime-telemetry:\n" + + " enabled: false\n" + + " example-instrumentation:\n" + + " string_key: value\n" + + " bool_key: true\n" + + " int_key: 1\n" + + " double_key: 1.1\n" + + " list_key:\n" + + " - value1\n" + + " - value2\n" + + " - true\n" + + " map_key:\n" + + " string_key1: value1\n" + + " string_key2: value2\n" + + " bool_key: true\n" + + " acme:\n" + + " full_name:\n" + + " preserved: true"; + + private ConfigProperties bridge; + private ConfigProperties emptyBridge; + + @BeforeEach + void setup() { + OpenTelemetryConfigurationModel model = + DeclarativeConfiguration.parse( + new ByteArrayInputStream(YAML.getBytes(StandardCharsets.UTF_8))); + SdkConfigProvider configProvider = SdkConfigProvider.create(model); + bridge = + new ConfigPropertiesUtil.DeclarativeConfigPropertiesBridge( + Objects.requireNonNull(configProvider.getInstrumentationConfig())); + + OpenTelemetryConfigurationModel emptyModel = + new OpenTelemetryConfigurationModel() + .withAdditionalProperty("instrumentation/development", new InstrumentationModel()); + SdkConfigProvider emptyConfigProvider = SdkConfigProvider.create(emptyModel); + emptyBridge = + new ConfigPropertiesUtil.DeclarativeConfigPropertiesBridge( + Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig())); + } + + @Test + void getProperties() { + // only properties starting with "otel.instrumentation." are resolved + // asking for properties which don't exist or inaccessible shouldn't result in an error + assertThat(bridge.getString("file_format")).isNull(); + assertThat(bridge.getString("file_format", "foo")).isEqualTo("foo"); + assertThat(emptyBridge.getBoolean("otel.instrumentation.common.default-enabled")).isNull(); + assertThat(emptyBridge.getBoolean("otel.instrumentation.common.default-enabled", true)) + .isTrue(); + + // common cases + assertThat(bridge.getBoolean("otel.instrumentation.common.default-enabled")).isTrue(); + assertThat(bridge.getBoolean("otel.instrumentation.runtime-telemetry.enabled")).isFalse(); + + // check all the types + Map expectedMap = new HashMap<>(); + expectedMap.put("string_key1", "value1"); + expectedMap.put("string_key2", "value2"); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.string_key")) + .isEqualTo("value"); + assertThat(bridge.getBoolean("otel.instrumentation.example-instrumentation.bool_key")).isTrue(); + assertThat(bridge.getInt("otel.instrumentation.example-instrumentation.int_key")).isEqualTo(1); + assertThat(bridge.getLong("otel.instrumentation.example-instrumentation.int_key")) + .isEqualTo(1L); + assertThat(bridge.getDuration("otel.instrumentation.example-instrumentation.int_key")) + .isEqualTo(Duration.ofMillis(1)); + assertThat(bridge.getDouble("otel.instrumentation.example-instrumentation.double_key")) + .isEqualTo(1.1); + assertThat(bridge.getList("otel.instrumentation.example-instrumentation.list_key")) + .isEqualTo(Arrays.asList("value1", "value2")); + assertThat(bridge.getMap("otel.instrumentation.example-instrumentation.map_key")) + .isEqualTo(expectedMap); + + // asking for properties with the wrong type returns null + assertThat(bridge.getBoolean("otel.instrumentation.example-instrumentation.string_key")) + .isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.bool_key")).isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.int_key")).isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.double_key")) + .isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.list_key")).isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.map_key")).isNull(); + + // check all the types + assertThat(bridge.getString("otel.instrumentation.other-instrumentation.string_key", "value")) + .isEqualTo("value"); + assertThat(bridge.getBoolean("otel.instrumentation.other-instrumentation.bool_key", true)) + .isTrue(); + assertThat(bridge.getInt("otel.instrumentation.other-instrumentation.int_key", 1)).isEqualTo(1); + assertThat(bridge.getLong("otel.instrumentation.other-instrumentation.int_key", 1L)) + .isEqualTo(1L); + assertThat( + bridge.getDuration( + "otel.instrumentation.other-instrumentation.int_key", Duration.ofMillis(1))) + .isEqualTo(Duration.ofMillis(1)); + assertThat(bridge.getDouble("otel.instrumentation.other-instrumentation.double_key", 1.1)) + .isEqualTo(1.1); + assertThat( + bridge.getList( + "otel.instrumentation.other-instrumentation.list_key", + Arrays.asList("value1", "value2"))) + .isEqualTo(Arrays.asList("value1", "value2")); + assertThat(bridge.getMap("otel.instrumentation.other-instrumentation.map_key", expectedMap)) + .isEqualTo(expectedMap); + + // verify vendor specific property names are preserved in unchanged form (prefix is not stripped + // as for otel.instrumentation.*) + assertThat(bridge.getBoolean("acme.full_name.preserved")).isTrue(); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 82364bf2a..4d2bc0bb6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -43,6 +43,7 @@ include(":baggage-processor") include(":compressors:compressor-zstd") include(":cloudfoundry-resources") include(":consistent-sampling") +include(":declarative-config-bridge") include(":dependencyManagement") include(":disk-buffering") include(":example") From 1dee070c944a51e14ddc2ea164fc3cecf09b02c0 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 17:25:41 +0200 Subject: [PATCH 04/41] support config bridge --- gcp-auth-extension/build.gradle.kts | 3 + .../contrib/gcp/auth/ConfigurableOption.java | 22 ++- ...thAutoConfigurationCustomizerProvider.java | 41 +++--- .../gcp/auth/GcpAuthCustomizerProvider.java | 131 ++++++++---------- .../auth/GcpAuthCustomizerProviderTest.java | 70 ++++++++++ 5 files changed, 170 insertions(+), 97 deletions(-) create mode 100644 gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java diff --git a/gcp-auth-extension/build.gradle.kts b/gcp-auth-extension/build.gradle.kts index d606782b0..093864c61 100644 --- a/gcp-auth-extension/build.gradle.kts +++ b/gcp-auth-extension/build.gradle.kts @@ -15,6 +15,8 @@ val agent: Configuration by configurations.creating { dependencies { implementation(platform("org.springframework.boot:spring-boot-dependencies:2.7.18")) + implementation(project(":declarative-config-bridge")) + annotationProcessor("com.google.auto.service:auto-service") // We use `compileOnly` dependency because during runtime all necessary classes are provided by // javaagent itself. @@ -37,6 +39,7 @@ dependencies { testImplementation("io.opentelemetry:opentelemetry-exporter-otlp") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations") testImplementation("org.awaitility:awaitility") 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 639207909..65c1c8e17 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 @@ -9,6 +9,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import java.util.Locale; import java.util.Optional; +import java.util.function.BiFunction; import java.util.function.Supplier; /** @@ -99,9 +100,16 @@ String getUserReadableName() { * @throws ConfigurationException if neither the environment variable nor the system property is * set. */ - String getConfiguredValue(ConfigProperties configProperties) { - String configuredValue = configProperties.getString(this.getSystemProperty()); - if (configuredValue != null && !configuredValue.isEmpty()) { + T getConfiguredValue(ConfigProperties configProperties, BiFunction extractor) { + T configuredValue = extractor.apply(configProperties, this.getSystemProperty()); + if (configuredValue instanceof String) { + String value = (String) configuredValue; + if (value.isEmpty()) { + configuredValue = null; // Treat empty string as not configured + } + } + + if (configuredValue != null) { return configuredValue; } else { throw new ConfigurationException( @@ -121,10 +129,10 @@ String getConfiguredValue(ConfigProperties configProperties) { * @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( - ConfigProperties configProperties, Supplier fallback) { + T getConfiguredValueWithFallback( + ConfigProperties configProperties, Supplier fallback, BiFunction extractor) { try { - return this.getConfiguredValue(configProperties); + return this.getConfiguredValue(configProperties, extractor); } catch (ConfigurationException e) { return fallback.get(); } @@ -140,7 +148,7 @@ String getConfiguredValueWithFallback( */ Optional getConfiguredValueAsOptional(ConfigProperties configProperties) { try { - return Optional.of(this.getConfiguredValue(configProperties)); + return Optional.of(this.getConfiguredValue(configProperties, ConfigProperties::getString)); } 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 b06359c38..ef6b40b52 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 @@ -25,7 +25,7 @@ import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.io.IOException; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -83,7 +83,7 @@ public class GcpAuthAutoConfigurationCustomizerProvider *
  • If the configured signal specific endpoint is a known GCP Telemetry API endpoint, * customizes only the signal specific exporter. * - * + *

    * The 'customization' performed includes customizing the exporters by adding required headers to * the export calls made and customizing the resource by adding required resource attributes to * enable GCP integration. @@ -151,17 +151,20 @@ private static MetricExporter customizeMetricExporter( } // Checks if the auth extension is configured to target the passed signal for authentication. - private static boolean isSignalTargeted(String checkSignal, ConfigProperties configProperties) { - String userSpecifiedTargetedSignals = - ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getConfiguredValueWithFallback( - configProperties, () -> SIGNAL_TYPE_ALL); - return Arrays.stream(userSpecifiedTargetedSignals.split(",")) - .map(String::trim) - .anyMatch( + static boolean isSignalTargeted(String checkSignal, ConfigProperties configProperties) { + return + targetSignals(configProperties).stream().anyMatch( targetedSignal -> targetedSignal.equals(checkSignal) || targetedSignal.equals(SIGNAL_TYPE_ALL)); } + static List targetSignals(ConfigProperties configProperties) { + return ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS + .getConfiguredValueWithFallback( + configProperties, () -> Collections.singletonList(SIGNAL_TYPE_ALL), + ConfigProperties::getList); + } + // Adds authorization headers to the calls made by the OtlpGrpcSpanExporter and // OtlpHttpSpanExporter. private static SpanExporter addAuthorizationHeaders( @@ -221,23 +224,29 @@ static Map getRequiredHeaderMap( // Add quota user project header if not detected by the auth library and user provided it via // system properties. if (!flattenedHeaders.containsKey(QUOTA_USER_PROJECT_HEADER)) { - Optional maybeConfiguredQuotaProjectId = - ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValueAsOptional( - configProperties); - maybeConfiguredQuotaProjectId.ifPresent( + getQuotaProjectId(configProperties).ifPresent( configuredQuotaProjectId -> flattenedHeaders.put(QUOTA_USER_PROJECT_HEADER, configuredQuotaProjectId)); } return flattenedHeaders; } + static Optional getQuotaProjectId(ConfigProperties configProperties) { + return ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValueAsOptional( + configProperties); + } + // 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(configProperties); Resource res = Resource.create( - Attributes.of(AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY), gcpProjectId)); + Attributes.of(AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY), + getProjectId(configProperties))); return resource.merge(res); } + + static String getProjectId(ConfigProperties configProperties) { + return ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue(configProperties, + ConfigProperties::getString); + } } diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java index e2512aab6..0aee50e95 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -5,15 +5,16 @@ package io.opentelemetry.contrib.gcp.auth; +import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_TRACES; +import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.isSignalTargeted; + import com.google.auth.oauth2.GoogleCredentials; import com.google.auto.service.AutoService; +import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel; @@ -23,7 +24,6 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleLogRecordProcessorModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleSpanProcessorModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; @@ -31,35 +31,60 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import javax.annotation.Nullable; @AutoService(DeclarativeConfigurationCustomizerProvider.class) public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { +// 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()); + + + @Override public void customize(DeclarativeConfigurationCustomizer customizer) { customizer.addModelCustomizer( model -> { + ConfigProperties configProperties = ConfigPropertiesUtil.resolveModel(model); GoogleCredentials credentials = GcpAuthAutoConfigurationCustomizerProvider.getCredentials(); - // todo pass config bridge - Map headerMap = - GcpAuthAutoConfigurationCustomizerProvider.getRequiredHeaderMap(credentials, null); - customizeMeter(model, headerMap); - // todo are loggers supported now (not covered in old variant)? - customizeLogger(model, headerMap); - customizeTracer(model, headerMap); + customize(model, credentials, configProperties); return model; }); } - private void customizeMeter( - OpenTelemetryConfigurationModel model, Map headerMap) { + static void customize(OpenTelemetryConfigurationModel model, + GoogleCredentials credentials, ConfigProperties configProperties) { + Map headerMap = + GcpAuthAutoConfigurationCustomizerProvider.getRequiredHeaderMap(credentials, + configProperties); + customizeMeter(model, headerMap, configProperties); + customizeTracer(model, headerMap, configProperties); + } + + private static void customizeMeter( + OpenTelemetryConfigurationModel model, Map headerMap, + ConfigProperties configProperties) { MeterProviderModel meterProvider = model.getMeterProvider(); if (meterProvider == null) { return; } + if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { + // todo + // 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; + } + for (MetricReaderModel reader : meterProvider.getReaders()) { if (reader.getPeriodic() != null) { addAuth(meterModelHeaders(reader.getPeriodic().getExporter()), headerMap); @@ -67,7 +92,8 @@ private void customizeMeter( } } - private List> meterModelHeaders(PushMetricExporterModel exporter) { + private static List> meterModelHeaders( + @Nullable PushMetricExporterModel exporter) { ArrayList> list = new ArrayList<>(); if (exporter == null) { return list; @@ -83,62 +109,23 @@ private List> meterModelHeaders(PushMetricExporte return list; } - private void customizeLogger( - OpenTelemetryConfigurationModel model, Map headerMap) { - LoggerProviderModel loggerProvider = model.getLoggerProvider(); - if (loggerProvider == null) { - return; - } - for (LogRecordProcessorModel processor : loggerProvider.getProcessors()) { - BatchLogRecordProcessorModel batch = processor.getBatch(); - if (batch != null) { - addAuth(logRecordModelHeaders(batch.getExporter()), headerMap); - } - SimpleLogRecordProcessorModel simple = processor.getSimple(); - if (simple != null) { - addAuth(logRecordModelHeaders(simple.getExporter()), headerMap); - } - } - } - - private List> logRecordModelHeaders( - LogRecordExporterModel exporter) { - ArrayList> list = new ArrayList<>(); - - if (exporter == null) { - return list; - } - OtlpGrpcExporterModel grpc = exporter.getOtlpGrpc(); - if (grpc != null) { - list.add(grpc.getHeaders()); - } - OtlpHttpExporterModel http = exporter.getOtlpHttp(); - if (http != null) { - list.add(http.getHeaders()); - } - return list; - } - - private void customizeTracer( - OpenTelemetryConfigurationModel model, Map headerMap) { + private static void customizeTracer( + OpenTelemetryConfigurationModel model, Map headerMap, + ConfigProperties configProperties) { TracerProviderModel tracerProvider = model.getTracerProvider(); if (tracerProvider == null) { return; } - // todo here we would want a simplified version of the declarative config bridge - // https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/DeclarativeConfigPropertiesBridge.java - // googleNode(model) - - // if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { - // todo - // 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; - // } + if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { + // todo + // 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; + } for (SpanProcessorModel processor : tracerProvider.getProcessors()) { BatchSpanProcessorModel batch = processor.getBatch(); @@ -152,12 +139,8 @@ private void customizeTracer( } } - private void googleNode(OpenTelemetryConfigurationModel model) { - // todo use declarative config bridge - } - - private List> spanExporterModelHeaders( - SpanExporterModel exporter) { + private static List> spanExporterModelHeaders( + @Nullable SpanExporterModel exporter) { ArrayList> list = new ArrayList<>(); if (exporter == null) { @@ -174,12 +157,12 @@ private List> spanExporterModelHeaders( return list; } - private void addAuth( + private static void addAuth( List> headerConsumers, Map headerMap) { headerConsumers.forEach(headers -> addHeaders(headers, headerMap)); } - private void addHeaders(List headers, Map add) { + private static void addHeaders(List headers, Map add) { add.forEach( (key, value) -> { if (headers.stream().noneMatch(header -> key.equals(header.getName()))) { diff --git a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java new file mode 100644 index 000000000..5d7fe46e8 --- /dev/null +++ b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java @@ -0,0 +1,70 @@ +package io.opentelemetry.contrib.gcp.auth; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.auth.oauth2.GoogleCredentials; +import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import org.junit.jupiter.api.Test; + +class GcpAuthCustomizerProviderTest { + + @Test + void declarativeConfig() throws IOException { + String yaml = + "file_format: 0.4\n" + + "tracer_provider:\n" + + " processors:\n" + + " - simple:\n" + + " exporter:\n" + + " otlp_http:\n" + + "meter_provider:\n" + + " readers:\n" + + " - periodic:\n" + + " exporter:\n" + + " otlp_http:\n" + + "instrumentation/development:\n" + + " java:\n" + + " google:\n" + + " cloud:\n" + + " project: p\n" + + " quota:\n" + + " project: qp\n" + + " otel:\n" + + " auth:\n" + + " target:\n" + + " signals: [metrics, traces]\n"; + + OpenTelemetryConfigurationModel model = DeclarativeConfiguration.parse( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + ConfigProperties properties = ConfigPropertiesUtil.resolveModel(model); + + assertThat( + GcpAuthAutoConfigurationCustomizerProvider.targetSignals(properties)).containsExactly( + "metrics", "traces" + ); + assertThat(GcpAuthAutoConfigurationCustomizerProvider.getProjectId(properties)).isEqualTo( + "p"); + assertThat(GcpAuthAutoConfigurationCustomizerProvider.getQuotaProjectId(properties)).contains( + "qp"); + + GoogleCredentials credentials = mock(GoogleCredentials.class); + when(credentials.getRequestMetadata()) + .thenReturn( + Collections.singletonMap("x-goog-user-project", Collections.singletonList("qp"))); + + GcpAuthCustomizerProvider.customize(model, credentials, properties); + + String header = "headers=\\[io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel@.*\\[name=x-goog-user-project,value=qp]"; + // both metrics and traces should have the header + assertThat(model.toString()).matches(String.format(".*%s.*%s.*", header, header)); + } +} From a2c30d75e83625383f1a89f7b363085eff33a805 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 18:07:01 +0200 Subject: [PATCH 05/41] support config bridge --- .../autoconfigure/ConfigPropertiesUtil.java | 5 + .../DeclarativeConfigPropertiesBridge.java | 207 ++++++++++-------- ...thAutoConfigurationCustomizerProvider.java | 28 ++- .../gcp/auth/GcpAuthCustomizerProvider.java | 65 +++--- .../auth/GcpAuthCustomizerProviderTest.java | 11 + 5 files changed, 168 insertions(+), 148 deletions(-) diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index af6cc6397..140a43297 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -52,4 +52,9 @@ public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel mode return new DeclarativeConfigPropertiesBridge(instrumentationConfig); } + + public static String propertyYamlPath(String propertyName) { + // todo test if this is correct + return DeclarativeConfigPropertiesBridge.yamlPath(propertyName); + } } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index 0721e4a69..c1d835bf5 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -49,110 +49,123 @@ */ final class DeclarativeConfigPropertiesBridge implements ConfigProperties { - private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; - - // The node at .instrumentation.java - private final DeclarativeConfigProperties instrumentationJavaNode; - - DeclarativeConfigPropertiesBridge(DeclarativeConfigProperties instrumentationNode) { - instrumentationJavaNode = instrumentationNode.getStructured("java", empty()); - } - - @Nullable - @Override - public String getString(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getString); - } - - @Nullable - @Override - public Boolean getBoolean(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getBoolean); - } - - @Nullable - @Override - public Integer getInt(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getInt); - } - - @Nullable - @Override - public Long getLong(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); - } - - @Nullable - @Override - public Double getDouble(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getDouble); - } - - @Nullable - @Override - public Duration getDuration(String propertyName) { - Long millis = getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); - if (millis == null) { - return null; + private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; + + // The node at .instrumentation.java + private final DeclarativeConfigProperties instrumentationJavaNode; + + DeclarativeConfigPropertiesBridge(DeclarativeConfigProperties instrumentationNode) { + instrumentationJavaNode = instrumentationNode.getStructured("java", empty()); } - return Duration.ofMillis(millis); - } - - @Override - public List getList(String propertyName) { - List propertyValue = - getPropertyValue( - propertyName, - (properties, lastPart) -> properties.getScalarList(lastPart, String.class)); - return propertyValue == null ? Collections.emptyList() : propertyValue; - } - - @Override - public Map getMap(String propertyName) { - DeclarativeConfigProperties propertyValue = - getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); - if (propertyValue == null) { - return Collections.emptyMap(); + + @Nullable + @Override + public String getString(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getString); } - Map result = new HashMap<>(); - propertyValue - .getPropertyKeys() - .forEach( - key -> { - String value = propertyValue.getString(key); - if (value == null) { - return; - } - result.put(key, value); - }); - return Collections.unmodifiableMap(result); - } - - @Nullable - private T getPropertyValue( - String property, BiFunction extractor) { - if (instrumentationJavaNode == null) { - return null; + + @Nullable + @Override + public Boolean getBoolean(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getBoolean); } - if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { - property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); + @Nullable + @Override + public Integer getInt(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getInt); } - // Split the remainder of the property on "." - String[] segments = property.split("\\."); - if (segments.length == 0) { - return null; + + @Nullable + @Override + public Long getLong(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + } + + @Nullable + @Override + public Double getDouble(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getDouble); + } + + @Nullable + @Override + public Duration getDuration(String propertyName) { + Long millis = getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + if (millis == null) { + return null; + } + return Duration.ofMillis(millis); } - // Extract the value by walking to the N-1 entry - DeclarativeConfigProperties target = instrumentationJavaNode; - if (segments.length > 1) { - for (int i = 0; i < segments.length - 1; i++) { - target = target.getStructured(segments[i], empty()); - } + @Override + public List getList(String propertyName) { + List propertyValue = + getPropertyValue( + propertyName, + (properties, lastPart) -> properties.getScalarList(lastPart, String.class)); + return propertyValue == null ? Collections.emptyList() : propertyValue; } - String lastPart = segments[segments.length - 1]; - return extractor.apply(target, lastPart); - } + @Override + public Map getMap(String propertyName) { + DeclarativeConfigProperties propertyValue = + getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); + if (propertyValue == null) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + propertyValue + .getPropertyKeys() + .forEach( + key -> { + String value = propertyValue.getString(key); + if (value == null) { + return; + } + result.put(key, value); + }); + return Collections.unmodifiableMap(result); + } + + @Nullable + private T getPropertyValue( + String property, BiFunction extractor) { + if (instrumentationJavaNode == null) { + return null; + } + + String[] segments = getSegments(property); + if (segments.length == 0) { + return null; + } + + // Extract the value by walking to the N-1 entry + DeclarativeConfigProperties target = instrumentationJavaNode; + if (segments.length > 1) { + for (int i = 0; i < segments.length - 1; i++) { + target = target.getStructured(segments[i], empty()); + } + } + String lastPart = segments[segments.length - 1]; + + return extractor.apply(target, lastPart); + } + + private static String[] getSegments(String property) { + if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { + property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); + } + // Split the remainder of the property on "." + return property.split("\\."); + } + + static String yamlPath(String property) { + String[] segments = getSegments(property); + if (segments.length == 0) { + throw new IllegalArgumentException("Invalid property: " + property); + } + + return "'instrumentation/development' / 'java' / '" + String.join("' / '", segments) + "'"; + } } 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 ef6b40b52..ed096e1d8 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 @@ -124,34 +124,38 @@ public int order() { private static SpanExporter customizeSpanExporter( SpanExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { - if (isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { + if (shouldConfigureExporter(SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, + 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, ConfigProperties configProperties) { - if (isSignalTargeted(SIGNAL_TYPE_METRICS, configProperties)) { + if (shouldConfigureExporter(SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, + configProperties)) { return addAuthorizationHeaders(exporter, credentials, configProperties); + } + return exporter; + } + + static boolean shouldConfigureExporter(String signal, + String fixSuggestion, + ConfigProperties configProperties) { + if (isSignalTargeted(signal, configProperties)) { + return true; } 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); + new String[] {signal, fixSuggestion}); + return false; } - return exporter; } // Checks if the auth extension is configured to target the passed signal for authentication. - static boolean isSignalTargeted(String checkSignal, ConfigProperties configProperties) { + private static boolean isSignalTargeted(String checkSignal, ConfigProperties configProperties) { return targetSignals(configProperties).stream().anyMatch( targetedSignal -> diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java index 0aee50e95..7ced14552 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -5,8 +5,9 @@ package io.opentelemetry.contrib.gcp.auth; +import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_METRICS; import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_TRACES; -import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.isSignalTargeted; +import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.shouldConfigureExporter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auto.service.AutoService; @@ -36,13 +37,12 @@ @AutoService(DeclarativeConfigurationCustomizerProvider.class) public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { -// 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 SIGNAL_TARGET_WARNING_FIX_SUGGESTION = + String.format( + "You may safely ignore this warning if it is intentional, otherwise please configure the '%s' by setting %s in the configuration file.", + ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getUserReadableName(), + ConfigPropertiesUtil.propertyYamlPath( + ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty())); @Override @@ -75,19 +75,12 @@ private static void customizeMeter( return; } - if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { - // todo - // 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; - } - - for (MetricReaderModel reader : meterProvider.getReaders()) { - if (reader.getPeriodic() != null) { - addAuth(meterModelHeaders(reader.getPeriodic().getExporter()), headerMap); + if (shouldConfigureExporter(SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, + configProperties)) { + for (MetricReaderModel reader : meterProvider.getReaders()) { + if (reader.getPeriodic() != null) { + addAuth(meterModelHeaders(reader.getPeriodic().getExporter()), headerMap); + } } } } @@ -117,26 +110,20 @@ private static void customizeTracer( return; } - if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) { - // todo - // 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; - } - - for (SpanProcessorModel processor : tracerProvider.getProcessors()) { - BatchSpanProcessorModel batch = processor.getBatch(); - if (batch != null) { - addAuth(spanExporterModelHeaders(batch.getExporter()), headerMap); - } - SimpleSpanProcessorModel simple = processor.getSimple(); - if (simple != null) { - addAuth(spanExporterModelHeaders(simple.getExporter()), headerMap); + if (shouldConfigureExporter(SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, + configProperties)) { + for (SpanProcessorModel processor : tracerProvider.getProcessors()) { + BatchSpanProcessorModel batch = processor.getBatch(); + if (batch != null) { + addAuth(spanExporterModelHeaders(batch.getExporter()), headerMap); + } + SimpleSpanProcessorModel simple = processor.getSimple(); + if (simple != null) { + addAuth(spanExporterModelHeaders(simple.getExporter()), headerMap); + } } } + } private static List> spanExporterModelHeaders( diff --git a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java index 5d7fe46e8..171c1825f 100644 --- a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java +++ b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java @@ -1,5 +1,6 @@ package io.opentelemetry.contrib.gcp.auth; +import static io.opentelemetry.contrib.gcp.auth.GcpAuthCustomizerProvider.SIGNAL_TARGET_WARNING_FIX_SUGGESTION; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -67,4 +68,14 @@ void declarativeConfig() throws IOException { // both metrics and traces should have the header assertThat(model.toString()).matches(String.format(".*%s.*%s.*", header, header)); } + + @Test + void fixSuggestion() { + assertThat(SIGNAL_TARGET_WARNING_FIX_SUGGESTION) + .isEqualTo("You may safely ignore this warning if it is intentional, " + + "otherwise please configure the 'Target Signals for Google Authentication Extension' " + + "by setting " + + "'instrumentation/development' / 'java' / 'google' / 'otel' / 'auth' / 'target' / " + + "'signals' in the configuration file."); + } } From 75640235d5a76dfe033addf2b4c64596de259c3d Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 18:15:47 +0200 Subject: [PATCH 06/41] copy declarative config bridge from instrumentation --- .../contrib/sdk/autoconfigure/ConfigPropertiesUtil.java | 1 - .../sdk/autoconfigure/ConfigPropertiesUtilTest.java | 7 +++++++ .../DeclarativeConfigPropertiesBridgeTest.java | 8 ++++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index 140a43297..ee71ccaad 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -54,7 +54,6 @@ public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel mode } public static String propertyYamlPath(String propertyName) { - // todo test if this is correct return DeclarativeConfigPropertiesBridge.yamlPath(propertyName); } } diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java index 8d88e9783..5d74a24a8 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java @@ -6,6 +6,7 @@ package io.opentelemetry.contrib.sdk.autoconfigure; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -84,4 +85,10 @@ void shouldUseConfigProviderForDeclarativeConfiguration_noInstrumentationConfig( assertThat(configProperties.getString("testProperty")).isEqualTo(null); } } + + @Test + void propertyYamlPath() { + assertThat(ConfigPropertiesUtil.propertyYamlPath("google.otel.auth.target.signals")) + .isEqualTo("'instrumentation/development' / 'java' / 'google' / 'otel' / 'auth' / 'target' / 'signals'"); + } } diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java index 5bff96e16..34b3a7036 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java @@ -3,7 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +import static org.assertj.core.api.Assertions.assertThat; + import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import java.io.ByteArrayInputStream; @@ -53,7 +57,7 @@ void setup() { new ByteArrayInputStream(YAML.getBytes(StandardCharsets.UTF_8))); SdkConfigProvider configProvider = SdkConfigProvider.create(model); bridge = - new ConfigPropertiesUtil.DeclarativeConfigPropertiesBridge( + new DeclarativeConfigPropertiesBridge( Objects.requireNonNull(configProvider.getInstrumentationConfig())); OpenTelemetryConfigurationModel emptyModel = @@ -61,7 +65,7 @@ void setup() { .withAdditionalProperty("instrumentation/development", new InstrumentationModel()); SdkConfigProvider emptyConfigProvider = SdkConfigProvider.create(emptyModel); emptyBridge = - new ConfigPropertiesUtil.DeclarativeConfigPropertiesBridge( + new DeclarativeConfigPropertiesBridge( Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig())); } From 858d71fa4bacf70af43f73bca1dcae3c85e0faca Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 18:16:20 +0200 Subject: [PATCH 07/41] format --- .../autoconfigure/ConfigPropertiesUtil.java | 71 +++--- .../DeclarativeConfigPropertiesBridge.java | 221 +++++++++--------- .../ConfigPropertiesUtilTest.java | 4 +- ...DeclarativeConfigPropertiesBridgeTest.java | 7 +- .../contrib/gcp/auth/ConfigurableOption.java | 7 +- ...thAutoConfigurationCustomizerProvider.java | 46 ++-- .../gcp/auth/GcpAuthCustomizerProvider.java | 26 ++- .../auth/GcpAuthCustomizerProviderTest.java | 37 +-- 8 files changed, 215 insertions(+), 204 deletions(-) diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index ee71ccaad..63db139f9 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -14,46 +14,43 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; public class ConfigPropertiesUtil { - private ConfigPropertiesUtil() { + private ConfigPropertiesUtil() {} + + /** Resolve {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ + public static ConfigProperties resolveConfigProperties( + AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { + ConfigProperties sdkConfigProperties = + AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); + if (sdkConfigProperties != null) { + return sdkConfigProperties; } + ConfigProvider configProvider = + AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); + if (configProvider != null) { + DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); - /** - * Resolve {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. - */ - public static ConfigProperties resolveConfigProperties( - AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { - ConfigProperties sdkConfigProperties = - AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); - if (sdkConfigProperties != null) { - return sdkConfigProperties; - } - ConfigProvider configProvider = - AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); - if (configProvider != null) { - DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); - - if (instrumentationConfig == null) { - instrumentationConfig = DeclarativeConfigProperties.empty(); - } - - return new DeclarativeConfigPropertiesBridge(instrumentationConfig); - } - // Should never happen - throw new IllegalStateException( - "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); - } - - public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel model) { - SdkConfigProvider configProvider = SdkConfigProvider.create(model); - DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); - if (instrumentationConfig == null) { - instrumentationConfig = DeclarativeConfigProperties.empty(); - } + if (instrumentationConfig == null) { + instrumentationConfig = DeclarativeConfigProperties.empty(); + } - return new DeclarativeConfigPropertiesBridge(instrumentationConfig); + return new DeclarativeConfigPropertiesBridge(instrumentationConfig); } - - public static String propertyYamlPath(String propertyName) { - return DeclarativeConfigPropertiesBridge.yamlPath(propertyName); + // Should never happen + throw new IllegalStateException( + "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); + } + + public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel model) { + SdkConfigProvider configProvider = SdkConfigProvider.create(model); + DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); + if (instrumentationConfig == null) { + instrumentationConfig = DeclarativeConfigProperties.empty(); } + + return new DeclarativeConfigPropertiesBridge(instrumentationConfig); + } + + public static String propertyYamlPath(String propertyName) { + return DeclarativeConfigPropertiesBridge.yamlPath(propertyName); + } } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index c1d835bf5..47173f7ac 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -5,18 +5,17 @@ package io.opentelemetry.contrib.sdk.autoconfigure; +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; + import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; - -import javax.annotation.Nullable; import java.time.Duration; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.BiFunction; - -import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; +import javax.annotation.Nullable; /** * A {@link ConfigProperties} which resolves properties based on {@link @@ -49,123 +48,123 @@ */ final class DeclarativeConfigPropertiesBridge implements ConfigProperties { - private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; - - // The node at .instrumentation.java - private final DeclarativeConfigProperties instrumentationJavaNode; - - DeclarativeConfigPropertiesBridge(DeclarativeConfigProperties instrumentationNode) { - instrumentationJavaNode = instrumentationNode.getStructured("java", empty()); + private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; + + // The node at .instrumentation.java + private final DeclarativeConfigProperties instrumentationJavaNode; + + DeclarativeConfigPropertiesBridge(DeclarativeConfigProperties instrumentationNode) { + instrumentationJavaNode = instrumentationNode.getStructured("java", empty()); + } + + @Nullable + @Override + public String getString(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getString); + } + + @Nullable + @Override + public Boolean getBoolean(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getBoolean); + } + + @Nullable + @Override + public Integer getInt(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getInt); + } + + @Nullable + @Override + public Long getLong(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + } + + @Nullable + @Override + public Double getDouble(String propertyName) { + return getPropertyValue(propertyName, DeclarativeConfigProperties::getDouble); + } + + @Nullable + @Override + public Duration getDuration(String propertyName) { + Long millis = getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + if (millis == null) { + return null; } - - @Nullable - @Override - public String getString(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getString); + return Duration.ofMillis(millis); + } + + @Override + public List getList(String propertyName) { + List propertyValue = + getPropertyValue( + propertyName, + (properties, lastPart) -> properties.getScalarList(lastPart, String.class)); + return propertyValue == null ? Collections.emptyList() : propertyValue; + } + + @Override + public Map getMap(String propertyName) { + DeclarativeConfigProperties propertyValue = + getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); + if (propertyValue == null) { + return Collections.emptyMap(); } - - @Nullable - @Override - public Boolean getBoolean(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getBoolean); + Map result = new HashMap<>(); + propertyValue + .getPropertyKeys() + .forEach( + key -> { + String value = propertyValue.getString(key); + if (value == null) { + return; + } + result.put(key, value); + }); + return Collections.unmodifiableMap(result); + } + + @Nullable + private T getPropertyValue( + String property, BiFunction extractor) { + if (instrumentationJavaNode == null) { + return null; } - @Nullable - @Override - public Integer getInt(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getInt); + String[] segments = getSegments(property); + if (segments.length == 0) { + return null; } - @Nullable - @Override - public Long getLong(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + // Extract the value by walking to the N-1 entry + DeclarativeConfigProperties target = instrumentationJavaNode; + if (segments.length > 1) { + for (int i = 0; i < segments.length - 1; i++) { + target = target.getStructured(segments[i], empty()); + } } + String lastPart = segments[segments.length - 1]; - @Nullable - @Override - public Double getDouble(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getDouble); - } - - @Nullable - @Override - public Duration getDuration(String propertyName) { - Long millis = getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); - if (millis == null) { - return null; - } - return Duration.ofMillis(millis); - } - - @Override - public List getList(String propertyName) { - List propertyValue = - getPropertyValue( - propertyName, - (properties, lastPart) -> properties.getScalarList(lastPart, String.class)); - return propertyValue == null ? Collections.emptyList() : propertyValue; - } + return extractor.apply(target, lastPart); + } - @Override - public Map getMap(String propertyName) { - DeclarativeConfigProperties propertyValue = - getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); - if (propertyValue == null) { - return Collections.emptyMap(); - } - Map result = new HashMap<>(); - propertyValue - .getPropertyKeys() - .forEach( - key -> { - String value = propertyValue.getString(key); - if (value == null) { - return; - } - result.put(key, value); - }); - return Collections.unmodifiableMap(result); + private static String[] getSegments(String property) { + if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { + property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); } - - @Nullable - private T getPropertyValue( - String property, BiFunction extractor) { - if (instrumentationJavaNode == null) { - return null; - } - - String[] segments = getSegments(property); - if (segments.length == 0) { - return null; - } - - // Extract the value by walking to the N-1 entry - DeclarativeConfigProperties target = instrumentationJavaNode; - if (segments.length > 1) { - for (int i = 0; i < segments.length - 1; i++) { - target = target.getStructured(segments[i], empty()); - } - } - String lastPart = segments[segments.length - 1]; - - return extractor.apply(target, lastPart); - } - - private static String[] getSegments(String property) { - if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { - property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); - } - // Split the remainder of the property on "." - return property.split("\\."); + // Split the remainder of the property on "." + return property.split("\\."); + } + + static String yamlPath(String property) { + String[] segments = getSegments(property); + if (segments.length == 0) { + throw new IllegalArgumentException("Invalid property: " + property); } - static String yamlPath(String property) { - String[] segments = getSegments(property); - if (segments.length == 0) { - throw new IllegalArgumentException("Invalid property: " + property); - } - - return "'instrumentation/development' / 'java' / '" + String.join("' / '", segments) + "'"; - } + return "'instrumentation/development' / 'java' / '" + String.join("' / '", segments) + "'"; + } } diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java index 5d74a24a8..9981ffdb2 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java @@ -5,7 +5,6 @@ package io.opentelemetry.contrib.sdk.autoconfigure; - import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -89,6 +88,7 @@ void shouldUseConfigProviderForDeclarativeConfiguration_noInstrumentationConfig( @Test void propertyYamlPath() { assertThat(ConfigPropertiesUtil.propertyYamlPath("google.otel.auth.target.signals")) - .isEqualTo("'instrumentation/development' / 'java' / 'google' / 'otel' / 'auth' / 'target' / 'signals'"); + .isEqualTo( + "'instrumentation/development' / 'java' / 'google' / 'otel' / 'auth' / 'target' / 'signals'"); } } diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java index 34b3a7036..caadda60b 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java @@ -1,8 +1,13 @@ -package io.opentelemetry.contrib.sdk.autoconfigure;/* +/* * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ +package io.opentelemetry.contrib.sdk.autoconfigure; /* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; 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 65c1c8e17..5756d1224 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 @@ -100,7 +100,8 @@ String getUserReadableName() { * @throws ConfigurationException if neither the environment variable nor the system property is * set. */ - T getConfiguredValue(ConfigProperties configProperties, BiFunction extractor) { + T getConfiguredValue( + ConfigProperties configProperties, BiFunction extractor) { T configuredValue = extractor.apply(configProperties, this.getSystemProperty()); if (configuredValue instanceof String) { String value = (String) configuredValue; @@ -130,7 +131,9 @@ T getConfiguredValue(ConfigProperties configProperties, BiFunction T getConfiguredValueWithFallback( - ConfigProperties configProperties, Supplier fallback, BiFunction extractor) { + ConfigProperties configProperties, + Supplier fallback, + BiFunction extractor) { try { return this.getConfiguredValue(configProperties, extractor); } catch (ConfigurationException e) { 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 ed096e1d8..a54dd677d 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 @@ -83,9 +83,9 @@ public class GcpAuthAutoConfigurationCustomizerProvider *

  • If the configured signal specific endpoint is a known GCP Telemetry API endpoint, * customizes only the signal specific exporter. * - *

    - * The 'customization' performed includes customizing the exporters by adding required headers to - * the export calls made and customizing the resource by adding required resource attributes to + * + *

    The 'customization' performed includes customizing the exporters by adding required headers + * to the export calls made and customizing the resource by adding required resource attributes to * enable GCP integration. * * @param autoConfiguration the AutoConfigurationCustomizer to customize. @@ -124,8 +124,8 @@ public int order() { private static SpanExporter customizeSpanExporter( SpanExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { - if (shouldConfigureExporter(SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, - configProperties)) { + if (shouldConfigureExporter( + SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, configProperties)) { return addAuthorizationHeaders(exporter, credentials, configProperties); } return exporter; @@ -133,16 +133,15 @@ private static SpanExporter customizeSpanExporter( private static MetricExporter customizeMetricExporter( MetricExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { - if (shouldConfigureExporter(SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, - configProperties)) { + if (shouldConfigureExporter( + SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, configProperties)) { return addAuthorizationHeaders(exporter, credentials, configProperties); } return exporter; } - static boolean shouldConfigureExporter(String signal, - String fixSuggestion, - ConfigProperties configProperties) { + static boolean shouldConfigureExporter( + String signal, String fixSuggestion, ConfigProperties configProperties) { if (isSignalTargeted(signal, configProperties)) { return true; } else { @@ -156,17 +155,17 @@ static boolean shouldConfigureExporter(String signal, // Checks if the auth extension is configured to target the passed signal for authentication. private static boolean isSignalTargeted(String checkSignal, ConfigProperties configProperties) { - return - targetSignals(configProperties).stream().anyMatch( + return targetSignals(configProperties).stream() + .anyMatch( targetedSignal -> targetedSignal.equals(checkSignal) || targetedSignal.equals(SIGNAL_TYPE_ALL)); } static List targetSignals(ConfigProperties configProperties) { - return ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS - .getConfiguredValueWithFallback( - configProperties, () -> Collections.singletonList(SIGNAL_TYPE_ALL), - ConfigProperties::getList); + return ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getConfiguredValueWithFallback( + configProperties, + () -> Collections.singletonList(SIGNAL_TYPE_ALL), + ConfigProperties::getList); } // Adds authorization headers to the calls made by the OtlpGrpcSpanExporter and @@ -228,9 +227,10 @@ static Map getRequiredHeaderMap( // Add quota user project header if not detected by the auth library and user provided it via // system properties. if (!flattenedHeaders.containsKey(QUOTA_USER_PROJECT_HEADER)) { - getQuotaProjectId(configProperties).ifPresent( - configuredQuotaProjectId -> - flattenedHeaders.put(QUOTA_USER_PROJECT_HEADER, configuredQuotaProjectId)); + getQuotaProjectId(configProperties) + .ifPresent( + configuredQuotaProjectId -> + flattenedHeaders.put(QUOTA_USER_PROJECT_HEADER, configuredQuotaProjectId)); } return flattenedHeaders; } @@ -244,13 +244,13 @@ static Optional getQuotaProjectId(ConfigProperties configProperties) { private static Resource customizeResource(Resource resource, ConfigProperties configProperties) { Resource res = Resource.create( - Attributes.of(AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY), - getProjectId(configProperties))); + Attributes.of( + AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY), getProjectId(configProperties))); return resource.merge(res); } static String getProjectId(ConfigProperties configProperties) { - return ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue(configProperties, - ConfigProperties::getString); + return ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue( + configProperties, ConfigProperties::getString); } } diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java index 7ced14552..90a3d17f2 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -44,7 +44,6 @@ public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustom ConfigPropertiesUtil.propertyYamlPath( ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty())); - @Override public void customize(DeclarativeConfigurationCustomizer customizer) { customizer.addModelCustomizer( @@ -58,25 +57,28 @@ public void customize(DeclarativeConfigurationCustomizer customizer) { }); } - static void customize(OpenTelemetryConfigurationModel model, - GoogleCredentials credentials, ConfigProperties configProperties) { + static void customize( + OpenTelemetryConfigurationModel model, + GoogleCredentials credentials, + ConfigProperties configProperties) { Map headerMap = - GcpAuthAutoConfigurationCustomizerProvider.getRequiredHeaderMap(credentials, - configProperties); + GcpAuthAutoConfigurationCustomizerProvider.getRequiredHeaderMap( + credentials, configProperties); customizeMeter(model, headerMap, configProperties); customizeTracer(model, headerMap, configProperties); } private static void customizeMeter( - OpenTelemetryConfigurationModel model, Map headerMap, + OpenTelemetryConfigurationModel model, + Map headerMap, ConfigProperties configProperties) { MeterProviderModel meterProvider = model.getMeterProvider(); if (meterProvider == null) { return; } - if (shouldConfigureExporter(SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, - configProperties)) { + if (shouldConfigureExporter( + SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, configProperties)) { for (MetricReaderModel reader : meterProvider.getReaders()) { if (reader.getPeriodic() != null) { addAuth(meterModelHeaders(reader.getPeriodic().getExporter()), headerMap); @@ -103,15 +105,16 @@ private static List> meterModelHeaders( } private static void customizeTracer( - OpenTelemetryConfigurationModel model, Map headerMap, + OpenTelemetryConfigurationModel model, + Map headerMap, ConfigProperties configProperties) { TracerProviderModel tracerProvider = model.getTracerProvider(); if (tracerProvider == null) { return; } - if (shouldConfigureExporter(SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, - configProperties)) { + if (shouldConfigureExporter( + SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, configProperties)) { for (SpanProcessorModel processor : tracerProvider.getProcessors()) { BatchSpanProcessorModel batch = processor.getBatch(); if (batch != null) { @@ -123,7 +126,6 @@ private static void customizeTracer( } } } - } private static List> spanExporterModelHeaders( diff --git a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java index 171c1825f..9ccff6129 100644 --- a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java +++ b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.contrib.gcp.auth; import static io.opentelemetry.contrib.gcp.auth.GcpAuthCustomizerProvider.SIGNAL_TARGET_WARNING_FIX_SUGGESTION; @@ -44,18 +49,16 @@ void declarativeConfig() throws IOException { + " target:\n" + " signals: [metrics, traces]\n"; - OpenTelemetryConfigurationModel model = DeclarativeConfiguration.parse( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + OpenTelemetryConfigurationModel model = + DeclarativeConfiguration.parse( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); ConfigProperties properties = ConfigPropertiesUtil.resolveModel(model); - assertThat( - GcpAuthAutoConfigurationCustomizerProvider.targetSignals(properties)).containsExactly( - "metrics", "traces" - ); - assertThat(GcpAuthAutoConfigurationCustomizerProvider.getProjectId(properties)).isEqualTo( - "p"); - assertThat(GcpAuthAutoConfigurationCustomizerProvider.getQuotaProjectId(properties)).contains( - "qp"); + assertThat(GcpAuthAutoConfigurationCustomizerProvider.targetSignals(properties)) + .containsExactly("metrics", "traces"); + assertThat(GcpAuthAutoConfigurationCustomizerProvider.getProjectId(properties)).isEqualTo("p"); + assertThat(GcpAuthAutoConfigurationCustomizerProvider.getQuotaProjectId(properties)) + .contains("qp"); GoogleCredentials credentials = mock(GoogleCredentials.class); when(credentials.getRequestMetadata()) @@ -64,7 +67,8 @@ void declarativeConfig() throws IOException { GcpAuthCustomizerProvider.customize(model, credentials, properties); - String header = "headers=\\[io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel@.*\\[name=x-goog-user-project,value=qp]"; + String header = + "headers=\\[io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel@.*\\[name=x-goog-user-project,value=qp]"; // both metrics and traces should have the header assertThat(model.toString()).matches(String.format(".*%s.*%s.*", header, header)); } @@ -72,10 +76,11 @@ void declarativeConfig() throws IOException { @Test void fixSuggestion() { assertThat(SIGNAL_TARGET_WARNING_FIX_SUGGESTION) - .isEqualTo("You may safely ignore this warning if it is intentional, " - + "otherwise please configure the 'Target Signals for Google Authentication Extension' " - + "by setting " - + "'instrumentation/development' / 'java' / 'google' / 'otel' / 'auth' / 'target' / " - + "'signals' in the configuration file."); + .isEqualTo( + "You may safely ignore this warning if it is intentional, " + + "otherwise please configure the 'Target Signals for Google Authentication Extension' " + + "by setting " + + "'instrumentation/development' / 'java' / 'google' / 'otel' / 'auth' / 'target' / " + + "'signals' in the configuration file."); } } From 3296368d84c20e0db0607105156ee461b59ca10e Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 18:21:06 +0200 Subject: [PATCH 08/41] cleanup --- .../contrib/gcp/auth/GcpAuthCustomizerProvider.java | 12 +++++------- .../gcp/auth/GcpAuthCustomizerProviderTest.java | 4 ++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java index 90a3d17f2..1b71800e4 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -37,7 +37,7 @@ @AutoService(DeclarativeConfigurationCustomizerProvider.class) public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { - static final String SIGNAL_TARGET_WARNING_FIX_SUGGESTION = + static final String SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION = String.format( "You may safely ignore this warning if it is intentional, otherwise please configure the '%s' by setting %s in the configuration file.", ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getUserReadableName(), @@ -48,10 +48,8 @@ public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustom public void customize(DeclarativeConfigurationCustomizer customizer) { customizer.addModelCustomizer( model -> { - ConfigProperties configProperties = ConfigPropertiesUtil.resolveModel(model); - GoogleCredentials credentials = - GcpAuthAutoConfigurationCustomizerProvider.getCredentials(); - customize(model, credentials, configProperties); + customize(model, GcpAuthAutoConfigurationCustomizerProvider.getCredentials(), + ConfigPropertiesUtil.resolveModel(model)); return model; }); @@ -78,7 +76,7 @@ private static void customizeMeter( } if (shouldConfigureExporter( - SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, configProperties)) { + SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION, configProperties)) { for (MetricReaderModel reader : meterProvider.getReaders()) { if (reader.getPeriodic() != null) { addAuth(meterModelHeaders(reader.getPeriodic().getExporter()), headerMap); @@ -114,7 +112,7 @@ private static void customizeTracer( } if (shouldConfigureExporter( - SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, configProperties)) { + SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION, configProperties)) { for (SpanProcessorModel processor : tracerProvider.getProcessors()) { BatchSpanProcessorModel batch = processor.getBatch(); if (batch != null) { diff --git a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java index 9ccff6129..fd469eae0 100644 --- a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java +++ b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java @@ -5,7 +5,7 @@ package io.opentelemetry.contrib.gcp.auth; -import static io.opentelemetry.contrib.gcp.auth.GcpAuthCustomizerProvider.SIGNAL_TARGET_WARNING_FIX_SUGGESTION; +import static io.opentelemetry.contrib.gcp.auth.GcpAuthCustomizerProvider.SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -75,7 +75,7 @@ void declarativeConfig() throws IOException { @Test void fixSuggestion() { - assertThat(SIGNAL_TARGET_WARNING_FIX_SUGGESTION) + assertThat(SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION) .isEqualTo( "You may safely ignore this warning if it is intentional, " + "otherwise please configure the 'Target Signals for Google Authentication Extension' " From b268964d4470b7bfb243dd4104dff2e53a5d3435 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 18:22:04 +0200 Subject: [PATCH 09/41] cleanup --- .../contrib/gcp/auth/GcpAuthCustomizerProvider.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java index 1b71800e4..297a47596 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -48,7 +48,9 @@ public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustom public void customize(DeclarativeConfigurationCustomizer customizer) { customizer.addModelCustomizer( model -> { - customize(model, GcpAuthAutoConfigurationCustomizerProvider.getCredentials(), + customize( + model, + GcpAuthAutoConfigurationCustomizerProvider.getCredentials(), ConfigPropertiesUtil.resolveModel(model)); return model; From 6054d35ee09e6f89ce7aefcb431e61011f487ac4 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 18:28:30 +0200 Subject: [PATCH 10/41] fix test --- declarative-config-bridge/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/declarative-config-bridge/build.gradle.kts b/declarative-config-bridge/build.gradle.kts index 66fb4658b..1da7432d0 100644 --- a/declarative-config-bridge/build.gradle.kts +++ b/declarative-config-bridge/build.gradle.kts @@ -14,4 +14,5 @@ dependencies { testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") + testImplementation("org.mockito:mockito-inline") } From 3c15bff865836406a7c8ed5437aa0f4ecc6c6870 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 19:14:29 +0200 Subject: [PATCH 11/41] fix --- .../contrib/gcp/auth/ConfigurableOption.java | 65 ++++++------------- ...thAutoConfigurationCustomizerProvider.java | 16 +++-- 2 files changed, 29 insertions(+), 52 deletions(-) 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 5756d1224..54649c7a6 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 @@ -8,9 +8,8 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import java.util.Locale; -import java.util.Optional; import java.util.function.BiFunction; -import java.util.function.Supplier; +import javax.annotation.Nullable; /** * An enum representing configurable options for a GCP Authentication Extension. Each option has a @@ -100,60 +99,36 @@ String getUserReadableName() { * @throws ConfigurationException if neither the environment variable nor the system property is * set. */ - T getConfiguredValue( + T getRequiredConfiguredValue( ConfigProperties configProperties, BiFunction extractor) { - T configuredValue = extractor.apply(configProperties, this.getSystemProperty()); - if (configuredValue instanceof String) { - String value = (String) configuredValue; - if (value.isEmpty()) { - configuredValue = null; // Treat empty string as not configured - } - } - - if (configuredValue != null) { - return configuredValue; - } else { + T configuredValue = getConfiguredValue(configProperties, extractor); + if (configuredValue == null) { throw new ConfigurationException( String.format( - "GCP Authentication Extension not configured properly: %s not configured. Configure it by exporting environment variable %s or system property %s", + "GCP Authentication Extension not configured properly: %s not configured. " + + "Configure it by exporting environment variable %s or system property %s", this.userReadableName, this.getEnvironmentVariable(), this.getSystemProperty())); } + return configuredValue; } /** - * Retrieves the value for this option, prioritizing environment variables and system properties. - * If neither an environment variable nor a system property is set for this option, the provided - * fallback function is used to determine the value. + * Retrieves the configured value for this option. This method checks the environment variable + * first and then the system property. * - * @param fallback A {@link Supplier} that provides the default value for the option when it is - * not explicitly configured via an environment variable or system property. - * @return The configured value for the option, obtained from the environment variable, system - * property, or the fallback function, in that order of precedence. + * @return The configured value as a string, or throws an exception if not configured. */ - T getConfiguredValueWithFallback( - ConfigProperties configProperties, - Supplier fallback, - BiFunction extractor) { - try { - return this.getConfiguredValue(configProperties, extractor); - } catch (ConfigurationException e) { - return fallback.get(); + @Nullable + T getConfiguredValue( + ConfigProperties configProperties, BiFunction extractor) { + T configuredValue = extractor.apply(configProperties, this.getSystemProperty()); + if (configuredValue instanceof String) { + String value = (String) configuredValue; + if (value.isEmpty()) { + configuredValue = null; // Treat empty string as not configured + } } - } - /** - * Retrieves the value for this option, prioritizing environment variables before system - * properties. If neither an environment variable nor a system property is set for this option, - * then an empty {@link Optional} is returned. - * - * @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(ConfigProperties configProperties) { - try { - return Optional.of(this.getConfiguredValue(configProperties, ConfigProperties::getString)); - } catch (ConfigurationException e) { - return Optional.empty(); - } + return configuredValue; } } 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 a54dd677d..8b241755f 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 @@ -162,10 +162,11 @@ private static boolean isSignalTargeted(String checkSignal, ConfigProperties con } static List targetSignals(ConfigProperties configProperties) { - return ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getConfiguredValueWithFallback( - configProperties, - () -> Collections.singletonList(SIGNAL_TYPE_ALL), - ConfigProperties::getList); + return Objects.requireNonNull( + ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getConfiguredValue( + configProperties, + (properties, name) -> + properties.getList(name, Collections.singletonList(SIGNAL_TYPE_ALL)))); } // Adds authorization headers to the calls made by the OtlpGrpcSpanExporter and @@ -236,8 +237,9 @@ static Map getRequiredHeaderMap( } static Optional getQuotaProjectId(ConfigProperties configProperties) { - return ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValueAsOptional( - configProperties); + return Optional.ofNullable( + ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValue( + configProperties, ConfigProperties::getString)); } // Updates the current resource with the attributes required for ingesting OTLP data on GCP. @@ -250,7 +252,7 @@ private static Resource customizeResource(Resource resource, ConfigProperties co } static String getProjectId(ConfigProperties configProperties) { - return ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue( + return ConfigurableOption.GOOGLE_CLOUD_PROJECT.getRequiredConfiguredValue( configProperties, ConfigProperties::getString); } } From a5fe6a28a2e288dd7cc071ee582f021792dec98b Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 14 Jul 2025 18:51:19 +0200 Subject: [PATCH 12/41] add property translation for inferred spans --- .../autoconfigure/ConfigPropertiesUtil.java | 10 +++- .../DeclarativeConfigPropertiesBridge.java | 16 ++++++- ...DeclarativeConfigPropertiesBridgeTest.java | 48 ++++++++++++------- inferred-spans/build.gradle.kts | 4 ++ .../InferredSpansCustomizerProvider.java | 29 +++++++++++ 5 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index 63db139f9..e5167c966 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -12,6 +12,8 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import java.util.Collections; +import java.util.Map; public class ConfigPropertiesUtil { private ConfigPropertiesUtil() {} @@ -33,7 +35,7 @@ public static ConfigProperties resolveConfigProperties( instrumentationConfig = DeclarativeConfigProperties.empty(); } - return new DeclarativeConfigPropertiesBridge(instrumentationConfig); + return new DeclarativeConfigPropertiesBridge(instrumentationConfig, Collections.emptyMap()); } // Should never happen throw new IllegalStateException( @@ -41,13 +43,17 @@ public static ConfigProperties resolveConfigProperties( } public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel model) { + return resolveModel(model, Collections.emptyMap()); + } + + public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel model, Map translationMap) { SdkConfigProvider configProvider = SdkConfigProvider.create(model); DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); if (instrumentationConfig == null) { instrumentationConfig = DeclarativeConfigProperties.empty(); } - return new DeclarativeConfigPropertiesBridge(instrumentationConfig); + return new DeclarativeConfigPropertiesBridge(instrumentationConfig, translationMap); } public static String propertyYamlPath(String propertyName) { diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index 47173f7ac..0cb6d17d6 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -52,9 +52,12 @@ final class DeclarativeConfigPropertiesBridge implements ConfigProperties { // The node at .instrumentation.java private final DeclarativeConfigProperties instrumentationJavaNode; + private final Map translationMap; - DeclarativeConfigPropertiesBridge(DeclarativeConfigProperties instrumentationNode) { + DeclarativeConfigPropertiesBridge(DeclarativeConfigProperties instrumentationNode, + Map translationMap) { instrumentationJavaNode = instrumentationNode.getStructured("java", empty()); + this.translationMap = translationMap; } @Nullable @@ -134,7 +137,7 @@ private T getPropertyValue( return null; } - String[] segments = getSegments(property); + String[] segments = getSegments(translate(property)); if (segments.length == 0) { return null; } @@ -151,6 +154,15 @@ private T getPropertyValue( return extractor.apply(target, lastPart); } + private String translate(String property) { + for (Map.Entry entry : translationMap.entrySet()) { + if (property.startsWith(entry.getKey())) { + return entry.getValue() + property.substring(entry.getKey().length()); + } + } + return property; + } + private static String[] getSegments(String property) { if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java index caadda60b..9ed47cd8c 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java @@ -4,9 +4,9 @@ */ package io.opentelemetry.contrib.sdk.autoconfigure; /* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ import static org.assertj.core.api.Assertions.assertThat; @@ -19,6 +19,7 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -57,13 +58,7 @@ class DeclarativeConfigPropertiesBridgeTest { @BeforeEach void setup() { - OpenTelemetryConfigurationModel model = - DeclarativeConfiguration.parse( - new ByteArrayInputStream(YAML.getBytes(StandardCharsets.UTF_8))); - SdkConfigProvider configProvider = SdkConfigProvider.create(model); - bridge = - new DeclarativeConfigPropertiesBridge( - Objects.requireNonNull(configProvider.getInstrumentationConfig())); + bridge = createBridge(Collections.emptyMap()); OpenTelemetryConfigurationModel emptyModel = new OpenTelemetryConfigurationModel() @@ -71,7 +66,18 @@ void setup() { SdkConfigProvider emptyConfigProvider = SdkConfigProvider.create(emptyModel); emptyBridge = new DeclarativeConfigPropertiesBridge( - Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig())); + Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig()), + Collections.emptyMap()); + } + + private static DeclarativeConfigPropertiesBridge createBridge( + Map translationMap) { + OpenTelemetryConfigurationModel model = + DeclarativeConfiguration.parse( + new ByteArrayInputStream(YAML.getBytes(StandardCharsets.UTF_8))); + return new DeclarativeConfigPropertiesBridge( + Objects.requireNonNull(SdkConfigProvider.create(model).getInstrumentationConfig()), + translationMap); } @Test @@ -126,21 +132,31 @@ void getProperties() { assertThat(bridge.getLong("otel.instrumentation.other-instrumentation.int_key", 1L)) .isEqualTo(1L); assertThat( - bridge.getDuration( - "otel.instrumentation.other-instrumentation.int_key", Duration.ofMillis(1))) + bridge.getDuration( + "otel.instrumentation.other-instrumentation.int_key", Duration.ofMillis(1))) .isEqualTo(Duration.ofMillis(1)); assertThat(bridge.getDouble("otel.instrumentation.other-instrumentation.double_key", 1.1)) .isEqualTo(1.1); assertThat( - bridge.getList( - "otel.instrumentation.other-instrumentation.list_key", - Arrays.asList("value1", "value2"))) + bridge.getList( + "otel.instrumentation.other-instrumentation.list_key", + Arrays.asList("value1", "value2"))) .isEqualTo(Arrays.asList("value1", "value2")); assertThat(bridge.getMap("otel.instrumentation.other-instrumentation.map_key", expectedMap)) .isEqualTo(expectedMap); + } + @Test + void vendor() { // verify vendor specific property names are preserved in unchanged form (prefix is not stripped // as for otel.instrumentation.*) assertThat(bridge.getBoolean("acme.full_name.preserved")).isTrue(); } + + @Test + void translation() { + DeclarativeConfigPropertiesBridge propertiesBridge = createBridge( + Collections.singletonMap("acme", "acme.full_name")); + assertThat(propertiesBridge.getBoolean("acme.preserved")).isTrue(); + } } diff --git a/inferred-spans/build.gradle.kts b/inferred-spans/build.gradle.kts index 98d5e33a3..bc89d6da9 100644 --- a/inferred-spans/build.gradle.kts +++ b/inferred-spans/build.gradle.kts @@ -9,10 +9,13 @@ description = "OpenTelemetry Java profiling based inferred spans module" otelJava.moduleName.set("io.opentelemetry.contrib.inferredspans") dependencies { + implementation(project(":declarative-config-bridge")) + annotationProcessor("com.google.auto.service:auto-service") compileOnly("com.google.auto.service:auto-service-annotations") compileOnly("io.opentelemetry:opentelemetry-sdk") compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") compileOnly("io.opentelemetry.semconv:opentelemetry-semconv") implementation("com.lmax:disruptor") implementation("org.jctools:jctools-core") @@ -25,6 +28,7 @@ dependencies { testImplementation("io.opentelemetry.semconv:opentelemetry-semconv") testImplementation("io.opentelemetry:opentelemetry-sdk") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") testImplementation("io.opentelemetry:opentelemetry-api-incubator") testImplementation("io.opentelemetry:opentelemetry-exporter-logging") diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java new file mode 100644 index 000000000..fa55f06e4 --- /dev/null +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.inferredspans; + +import com.google.auto.service.AutoService; +import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; +import java.util.Collections; + +@AutoService(DeclarativeConfigurationCustomizerProvider.class) +public class InferredSpansCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { + + @Override + public void customize(DeclarativeConfigurationCustomizer customizer) { + customizer.addModelCustomizer( + model -> { + ConfigProperties configProperties = ConfigPropertiesUtil.resolveModel(model, + Collections.singletonMap("otel.inferred.spans", "inferred_spans")); + + return model; + }); + } + +} From 7c4879448d0df7093664c7ea641f756c1d39e729 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 08:10:49 +0200 Subject: [PATCH 13/41] inferred spans --- .../autoconfigure/ConfigPropertiesUtil.java | 27 +++++---- .../DeclarativeConfigPropertiesBridge.java | 4 +- ...DeclarativeConfigPropertiesBridgeTest.java | 20 +++---- .../InferredSpansAutoConfig.java | 56 +++++++++++-------- .../InferredSpansComponentProvider.java | 33 +++++++++++ .../InferredSpansCustomizerProvider.java | 19 ++++++- .../InferredSpansCustomizerProviderTest.java | 41 ++++++++++++++ 7 files changed, 152 insertions(+), 48 deletions(-) create mode 100644 inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java create mode 100644 inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index e5167c966..da52fb1c9 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -14,6 +14,7 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import java.util.Collections; import java.util.Map; +import javax.annotation.Nullable; public class ConfigPropertiesUtil { private ConfigPropertiesUtil() {} @@ -29,13 +30,8 @@ public static ConfigProperties resolveConfigProperties( ConfigProvider configProvider = AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); if (configProvider != null) { - DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); - - if (instrumentationConfig == null) { - instrumentationConfig = DeclarativeConfigProperties.empty(); - } - - return new DeclarativeConfigPropertiesBridge(instrumentationConfig, Collections.emptyMap()); + return resolveInstrumentationConfig( + configProvider.getInstrumentationConfig(), Collections.emptyMap()); } // Should never happen throw new IllegalStateException( @@ -46,9 +42,20 @@ public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel mode return resolveModel(model, Collections.emptyMap()); } - public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel model, Map translationMap) { - SdkConfigProvider configProvider = SdkConfigProvider.create(model); - DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); + public static ConfigProperties resolveModel( + OpenTelemetryConfigurationModel model, Map translationMap) { + return resolveInstrumentationConfig( + SdkConfigProvider.create(model).getInstrumentationConfig(), translationMap); + } + + public static ConfigProperties resolveInstrumentationConfig( + @Nullable DeclarativeConfigProperties instrumentationConfig) { + return resolveInstrumentationConfig(instrumentationConfig, Collections.emptyMap()); + } + + public static ConfigProperties resolveInstrumentationConfig( + @Nullable DeclarativeConfigProperties instrumentationConfig, + Map translationMap) { if (instrumentationConfig == null) { instrumentationConfig = DeclarativeConfigProperties.empty(); } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index 0cb6d17d6..11a16afbb 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -54,8 +54,8 @@ final class DeclarativeConfigPropertiesBridge implements ConfigProperties { private final DeclarativeConfigProperties instrumentationJavaNode; private final Map translationMap; - DeclarativeConfigPropertiesBridge(DeclarativeConfigProperties instrumentationNode, - Map translationMap) { + DeclarativeConfigPropertiesBridge( + DeclarativeConfigProperties instrumentationNode, Map translationMap) { instrumentationJavaNode = instrumentationNode.getStructured("java", empty()); this.translationMap = translationMap; } diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java index 9ed47cd8c..a7722c5b9 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java @@ -4,9 +4,9 @@ */ package io.opentelemetry.contrib.sdk.autoconfigure; /* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ import static org.assertj.core.api.Assertions.assertThat; @@ -132,15 +132,15 @@ void getProperties() { assertThat(bridge.getLong("otel.instrumentation.other-instrumentation.int_key", 1L)) .isEqualTo(1L); assertThat( - bridge.getDuration( - "otel.instrumentation.other-instrumentation.int_key", Duration.ofMillis(1))) + bridge.getDuration( + "otel.instrumentation.other-instrumentation.int_key", Duration.ofMillis(1))) .isEqualTo(Duration.ofMillis(1)); assertThat(bridge.getDouble("otel.instrumentation.other-instrumentation.double_key", 1.1)) .isEqualTo(1.1); assertThat( - bridge.getList( - "otel.instrumentation.other-instrumentation.list_key", - Arrays.asList("value1", "value2"))) + bridge.getList( + "otel.instrumentation.other-instrumentation.list_key", + Arrays.asList("value1", "value2"))) .isEqualTo(Arrays.asList("value1", "value2")); assertThat(bridge.getMap("otel.instrumentation.other-instrumentation.map_key", expectedMap)) .isEqualTo(expectedMap); @@ -155,8 +155,8 @@ void vendor() { @Test void translation() { - DeclarativeConfigPropertiesBridge propertiesBridge = createBridge( - Collections.singletonMap("acme", "acme.full_name")); + DeclarativeConfigPropertiesBridge propertiesBridge = + createBridge(Collections.singletonMap("acme", "acme.full_name")); assertThat(propertiesBridge.getBoolean("acme.preserved")).isTrue(); } } diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java index 9c8118ec5..39f99808c 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java @@ -44,30 +44,8 @@ public class InferredSpansAutoConfig implements AutoConfigurationCustomizerProvi public void customize(AutoConfigurationCustomizer config) { config.addTracerProviderCustomizer( (providerBuilder, properties) -> { - if (properties.getBoolean(ENABLED_OPTION, false)) { - InferredSpansProcessorBuilder builder = InferredSpansProcessor.builder(); - - PropertiesApplier applier = new PropertiesApplier(properties); - - applier.applyBool(LOGGING_OPTION, builder::profilerLoggingEnabled); - applier.applyBool(DIAGNOSTIC_FILES_OPTION, builder::backupDiagnosticFiles); - applier.applyInt(SAFEMODE_OPTION, builder::asyncProfilerSafeMode); - applier.applyBool(POSTPROCESSING_OPTION, builder::postProcessingEnabled); - applier.applyDuration(SAMPLING_INTERVAL_OPTION, builder::samplingInterval); - applier.applyDuration(MIN_DURATION_OPTION, builder::inferredSpansMinDuration); - applier.applyWildcards(INCLUDED_CLASSES_OPTION, builder::includedClasses); - applier.applyWildcards(EXCLUDED_CLASSES_OPTION, builder::excludedClasses); - applier.applyDuration(INTERVAL_OPTION, builder::profilerInterval); - applier.applyDuration(DURATION_OPTION, builder::profilingDuration); - applier.applyString(LIB_DIRECTORY_OPTION, builder::profilerLibDirectory); - - String parentOverrideHandlerName = properties.getString(PARENT_OVERRIDE_HANDLER_OPTION); - if (parentOverrideHandlerName != null && !parentOverrideHandlerName.isEmpty()) { - builder.parentOverrideHandler( - constructParentOverrideHandler(parentOverrideHandlerName)); - } - - providerBuilder.addSpanProcessor(builder.build()); + if (isEnabled(properties)) { + providerBuilder.addSpanProcessor(create(properties)); } else { log.finest( "Not enabling inferred spans processor because " + ENABLED_OPTION + " is not set"); @@ -76,6 +54,36 @@ public void customize(AutoConfigurationCustomizer config) { }); } + static InferredSpansProcessor create(ConfigProperties properties) { + InferredSpansProcessorBuilder builder = InferredSpansProcessor.builder(); + + PropertiesApplier applier = new PropertiesApplier(properties); + + applier.applyBool(LOGGING_OPTION, builder::profilerLoggingEnabled); + applier.applyBool(DIAGNOSTIC_FILES_OPTION, builder::backupDiagnosticFiles); + applier.applyInt(SAFEMODE_OPTION, builder::asyncProfilerSafeMode); + applier.applyBool(POSTPROCESSING_OPTION, builder::postProcessingEnabled); + applier.applyDuration(SAMPLING_INTERVAL_OPTION, builder::samplingInterval); + applier.applyDuration(MIN_DURATION_OPTION, builder::inferredSpansMinDuration); + applier.applyWildcards(INCLUDED_CLASSES_OPTION, builder::includedClasses); + applier.applyWildcards(EXCLUDED_CLASSES_OPTION, builder::excludedClasses); + applier.applyDuration(INTERVAL_OPTION, builder::profilerInterval); + applier.applyDuration(DURATION_OPTION, builder::profilingDuration); + applier.applyString(LIB_DIRECTORY_OPTION, builder::profilerLibDirectory); + + String parentOverrideHandlerName = properties.getString(PARENT_OVERRIDE_HANDLER_OPTION); + if (parentOverrideHandlerName != null && !parentOverrideHandlerName.isEmpty()) { + builder.parentOverrideHandler(constructParentOverrideHandler(parentOverrideHandlerName)); + } + + InferredSpansProcessor spanProcessor = builder.build(); + return spanProcessor; + } + + static boolean isEnabled(ConfigProperties properties) { + return properties.getBoolean(ENABLED_OPTION, false); + } + @SuppressWarnings("unchecked") private static BiConsumer constructParentOverrideHandler(String name) { try { diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java new file mode 100644 index 000000000..7563f3596 --- /dev/null +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.inferredspans; + +import com.google.auto.service.AutoService; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.trace.SpanProcessor; + +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class InferredSpansComponentProvider implements ComponentProvider { + @Override + public String getName() { + return "inferred_spans"; + } + + @Override + public SpanProcessor create(DeclarativeConfigProperties config) { + return InferredSpansAutoConfig.create( + ConfigPropertiesUtil.resolveInstrumentationConfig( + config, InferredSpansCustomizerProvider.TRANSLATION_MAP)); + } + + @Override + public Class getType() { + return SpanProcessor.class; + } +} diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java index fa55f06e4..744f9b9e4 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java @@ -10,20 +10,35 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; import java.util.Collections; +import java.util.Map; @AutoService(DeclarativeConfigurationCustomizerProvider.class) public class InferredSpansCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { + static final Map TRANSLATION_MAP = + Collections.singletonMap("otel.inferred.spans", "inferred_spans"); + @Override public void customize(DeclarativeConfigurationCustomizer customizer) { customizer.addModelCustomizer( model -> { - ConfigProperties configProperties = ConfigPropertiesUtil.resolveModel(model, - Collections.singletonMap("otel.inferred.spans", "inferred_spans")); + ConfigProperties configProperties = + ConfigPropertiesUtil.resolveModel(model, TRANSLATION_MAP); + + TracerProviderModel tracerProvider = model.getTracerProvider(); + if (tracerProvider != null && InferredSpansAutoConfig.isEnabled(configProperties)) { + tracerProvider.getProcessors().add(create()); + } return model; }); } + @SuppressWarnings("NullAway") + private static SpanProcessorModel create() { + return new SpanProcessorModel().withAdditionalProperty("inferred_spans", null); + } } diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java new file mode 100644 index 000000000..3b83a923f --- /dev/null +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.inferredspans; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class InferredSpansCustomizerProviderTest { + + @Test + void declarativeConfig() { + String yaml = + "file_format: 0.4\n" + + "tracer_provider:\n" + + "instrumentation/development:\n" + + " java:\n" + + " inferred_spans:\n" + + " enabled: true\n"; + + OpenTelemetryConfigurationModel model = + DeclarativeConfiguration.parse( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + + new InferredSpansCustomizerProvider() + .customize( + c -> { + OpenTelemetryConfigurationModel configurationModel = c.apply(model); + assertThat(configurationModel.toString()) + .matches( + ".*SpanProcessorModel@.{8}\\[batch=,simple=,additionalProperties=\\{inferred_spans=null}.*"); + }); + } +} From 2854093e91634e96e5610fabd238d4ba405a011f Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 10:02:24 +0200 Subject: [PATCH 14/41] inferred spans --- .../autoconfigure/ConfigPropertiesUtil.java | 10 ++-- .../DeclarativeConfigPropertiesBridge.java | 28 ++++++++--- ...DeclarativeConfigPropertiesBridgeTest.java | 4 +- .../InferredSpansAutoConfig.java | 26 +++++----- .../InferredSpansComponentProvider.java | 7 ++- .../InferredSpansCustomizerProviderTest.java | 47 ++++++++++--------- 6 files changed, 72 insertions(+), 50 deletions(-) diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index da52fb1c9..457e49b90 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -56,11 +56,13 @@ public static ConfigProperties resolveInstrumentationConfig( public static ConfigProperties resolveInstrumentationConfig( @Nullable DeclarativeConfigProperties instrumentationConfig, Map translationMap) { - if (instrumentationConfig == null) { - instrumentationConfig = DeclarativeConfigProperties.empty(); - } + return DeclarativeConfigPropertiesBridge.fromInstrumentationConfig( + instrumentationConfig, translationMap); + } - return new DeclarativeConfigPropertiesBridge(instrumentationConfig, translationMap); + public static ConfigProperties resolveConfig( + @Nullable DeclarativeConfigProperties config, Map translationMap) { + return DeclarativeConfigPropertiesBridge.create(config, translationMap); } public static String propertyYamlPath(String propertyName) { diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index 11a16afbb..8acdc32a1 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -50,13 +50,27 @@ final class DeclarativeConfigPropertiesBridge implements ConfigProperties { private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; - // The node at .instrumentation.java - private final DeclarativeConfigProperties instrumentationJavaNode; + @Nullable private final DeclarativeConfigProperties baseNode; private final Map translationMap; - DeclarativeConfigPropertiesBridge( - DeclarativeConfigProperties instrumentationNode, Map translationMap) { - instrumentationJavaNode = instrumentationNode.getStructured("java", empty()); + static DeclarativeConfigPropertiesBridge fromInstrumentationConfig( + @Nullable DeclarativeConfigProperties instrumentationConfig, + Map translationMap) { + if (instrumentationConfig == null) { + instrumentationConfig = DeclarativeConfigProperties.empty(); + } + return new DeclarativeConfigPropertiesBridge( + instrumentationConfig.getStructured("java", empty()), translationMap); + } + + static DeclarativeConfigPropertiesBridge create( + @Nullable DeclarativeConfigProperties node, Map translationMap) { + return new DeclarativeConfigPropertiesBridge(node, translationMap); + } + + private DeclarativeConfigPropertiesBridge( + @Nullable DeclarativeConfigProperties baseNode, Map translationMap) { + this.baseNode = baseNode; this.translationMap = translationMap; } @@ -133,7 +147,7 @@ public Map getMap(String propertyName) { @Nullable private T getPropertyValue( String property, BiFunction extractor) { - if (instrumentationJavaNode == null) { + if (baseNode == null) { return null; } @@ -143,7 +157,7 @@ private T getPropertyValue( } // Extract the value by walking to the N-1 entry - DeclarativeConfigProperties target = instrumentationJavaNode; + DeclarativeConfigProperties target = baseNode; if (segments.length > 1) { for (int i = 0; i < segments.length - 1; i++) { target = target.getStructured(segments[i], empty()); diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java index a7722c5b9..e02940d1c 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java @@ -65,7 +65,7 @@ void setup() { .withAdditionalProperty("instrumentation/development", new InstrumentationModel()); SdkConfigProvider emptyConfigProvider = SdkConfigProvider.create(emptyModel); emptyBridge = - new DeclarativeConfigPropertiesBridge( + DeclarativeConfigPropertiesBridge.fromInstrumentationConfig( Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig()), Collections.emptyMap()); } @@ -75,7 +75,7 @@ private static DeclarativeConfigPropertiesBridge createBridge( OpenTelemetryConfigurationModel model = DeclarativeConfiguration.parse( new ByteArrayInputStream(YAML.getBytes(StandardCharsets.UTF_8))); - return new DeclarativeConfigPropertiesBridge( + return DeclarativeConfigPropertiesBridge.fromInstrumentationConfig( Objects.requireNonNull(SdkConfigProvider.create(model).getInstrumentationConfig()), translationMap); } diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java index 39f99808c..c10b81db6 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java @@ -11,8 +11,10 @@ import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.trace.SpanProcessor; import java.time.Duration; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -44,17 +46,20 @@ public class InferredSpansAutoConfig implements AutoConfigurationCustomizerProvi public void customize(AutoConfigurationCustomizer config) { config.addTracerProviderCustomizer( (providerBuilder, properties) -> { - if (isEnabled(properties)) { - providerBuilder.addSpanProcessor(create(properties)); - } else { - log.finest( - "Not enabling inferred spans processor because " + ENABLED_OPTION + " is not set"); - } + providerBuilder.addSpanProcessor(create(properties, /* enableByDefault= */ false)); return providerBuilder; }); } - static InferredSpansProcessor create(ConfigProperties properties) { + static SpanProcessor create(ConfigProperties properties, boolean enableByDefault) { + if (!properties.getBoolean(ENABLED_OPTION, enableByDefault)) { + log.finest( + "Not creating inferred spans processor because " + + ENABLED_OPTION + + " is not set to true"); + return SpanProcessor.composite(Collections.emptyList()); + } + InferredSpansProcessorBuilder builder = InferredSpansProcessor.builder(); PropertiesApplier applier = new PropertiesApplier(properties); @@ -76,12 +81,7 @@ static InferredSpansProcessor create(ConfigProperties properties) { builder.parentOverrideHandler(constructParentOverrideHandler(parentOverrideHandlerName)); } - InferredSpansProcessor spanProcessor = builder.build(); - return spanProcessor; - } - - static boolean isEnabled(ConfigProperties properties) { - return properties.getBoolean(ENABLED_OPTION, false); + return builder.build(); } @SuppressWarnings("unchecked") diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java index 7563f3596..545bcc80c 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java @@ -10,10 +10,12 @@ import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; import io.opentelemetry.sdk.trace.SpanProcessor; +import java.util.Collections; @SuppressWarnings("rawtypes") @AutoService(ComponentProvider.class) public class InferredSpansComponentProvider implements ComponentProvider { + @Override public String getName() { return "inferred_spans"; @@ -22,8 +24,9 @@ public String getName() { @Override public SpanProcessor create(DeclarativeConfigProperties config) { return InferredSpansAutoConfig.create( - ConfigPropertiesUtil.resolveInstrumentationConfig( - config, InferredSpansCustomizerProvider.TRANSLATION_MAP)); + ConfigPropertiesUtil.resolveConfig( + config, Collections.singletonMap("otel.inferred.spans.", "")), + /* enableByDefault= */ true); } @Override diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java index 3b83a923f..0e5cc85cd 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java @@ -5,37 +5,40 @@ package io.opentelemetry.contrib.inferredspans; -import static org.assertj.core.api.Assertions.assertThat; - import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import org.junit.jupiter.api.Test; + import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; -import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; class InferredSpansCustomizerProviderTest { + private static final String FQDN = + "spanProcessor=io.opentelemetry.contrib.inferredspans.InferredSpansProcessor"; + + @Test + void enabled() { + assertThat(create("")).contains(FQDN); + } + @Test - void declarativeConfig() { + void disabled() { + assertThat(create("enabled: false")).doesNotContain(FQDN); + } + + private static String create(String enabled) { String yaml = "file_format: 0.4\n" + "tracer_provider:\n" - + "instrumentation/development:\n" - + " java:\n" - + " inferred_spans:\n" - + " enabled: true\n"; - - OpenTelemetryConfigurationModel model = - DeclarativeConfiguration.parse( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); - - new InferredSpansCustomizerProvider() - .customize( - c -> { - OpenTelemetryConfigurationModel configurationModel = c.apply(model); - assertThat(configurationModel.toString()) - .matches( - ".*SpanProcessorModel@.{8}\\[batch=,simple=,additionalProperties=\\{inferred_spans=null}.*"); - }); + + " processors:\n" + + " - inferred_spans:\n" + + " " + + enabled + + "\n"; + return DeclarativeConfiguration.parseAndCreate( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))) + .toString(); } } From 0eb9b1e80acca344abebfd50036b6fbcf4d649cc Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 10:24:46 +0200 Subject: [PATCH 15/41] inferred spans --- .../InferredSpansAutoConfig.java | 18 +++----- .../InferredSpansComponentProvider.java | 3 +- .../InferredSpansCustomizerProvider.java | 44 ------------------- .../InferredSpansCustomizerProviderTest.java | 41 +++++++++-------- 4 files changed, 30 insertions(+), 76 deletions(-) delete mode 100644 inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java index c10b81db6..f944841d7 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java @@ -14,7 +14,6 @@ import io.opentelemetry.sdk.trace.SpanProcessor; import java.time.Duration; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -46,20 +45,17 @@ public class InferredSpansAutoConfig implements AutoConfigurationCustomizerProvi public void customize(AutoConfigurationCustomizer config) { config.addTracerProviderCustomizer( (providerBuilder, properties) -> { - providerBuilder.addSpanProcessor(create(properties, /* enableByDefault= */ false)); + if (properties.getBoolean(ENABLED_OPTION, false)) { + providerBuilder.addSpanProcessor(create(properties)); + } else { + log.finest( + "Not enabling inferred spans processor because " + ENABLED_OPTION + " is not set"); + } return providerBuilder; }); } - static SpanProcessor create(ConfigProperties properties, boolean enableByDefault) { - if (!properties.getBoolean(ENABLED_OPTION, enableByDefault)) { - log.finest( - "Not creating inferred spans processor because " - + ENABLED_OPTION - + " is not set to true"); - return SpanProcessor.composite(Collections.emptyList()); - } - + static SpanProcessor create(ConfigProperties properties) { InferredSpansProcessorBuilder builder = InferredSpansProcessor.builder(); PropertiesApplier applier = new PropertiesApplier(properties); diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java index 545bcc80c..21101d639 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java @@ -25,8 +25,7 @@ public String getName() { public SpanProcessor create(DeclarativeConfigProperties config) { return InferredSpansAutoConfig.create( ConfigPropertiesUtil.resolveConfig( - config, Collections.singletonMap("otel.inferred.spans.", "")), - /* enableByDefault= */ true); + config, Collections.singletonMap("otel.inferred.spans.", ""))); } @Override diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java deleted file mode 100644 index 744f9b9e4..000000000 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.inferredspans; - -import com.google.auto.service.AutoService; -import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; -import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; -import java.util.Collections; -import java.util.Map; - -@AutoService(DeclarativeConfigurationCustomizerProvider.class) -public class InferredSpansCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { - - static final Map TRANSLATION_MAP = - Collections.singletonMap("otel.inferred.spans", "inferred_spans"); - - @Override - public void customize(DeclarativeConfigurationCustomizer customizer) { - customizer.addModelCustomizer( - model -> { - ConfigProperties configProperties = - ConfigPropertiesUtil.resolveModel(model, TRANSLATION_MAP); - - TracerProviderModel tracerProvider = model.getTracerProvider(); - if (tracerProvider != null && InferredSpansAutoConfig.isEnabled(configProperties)) { - tracerProvider.getProcessors().add(create()); - } - - return model; - }); - } - - @SuppressWarnings("NullAway") - private static SpanProcessorModel create() { - return new SpanProcessorModel().withAdditionalProperty("inferred_spans", null); - } -} diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java index 0e5cc85cd..cca693e42 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java @@ -5,6 +5,7 @@ package io.opentelemetry.contrib.inferredspans; +import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; import org.junit.jupiter.api.Test; @@ -15,30 +16,32 @@ class InferredSpansCustomizerProviderTest { - private static final String FQDN = - "spanProcessor=io.opentelemetry.contrib.inferredspans.InferredSpansProcessor"; - - @Test - void enabled() { - assertThat(create("")).contains(FQDN); - } - @Test - void disabled() { - assertThat(create("enabled: false")).doesNotContain(FQDN); - } - - private static String create(String enabled) { + void declarativeConfig() { String yaml = "file_format: 0.4\n" + "tracer_provider:\n" + " processors:\n" + " - inferred_spans:\n" - + " " - + enabled - + "\n"; - return DeclarativeConfiguration.parseAndCreate( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))) - .toString(); + + " backup:\n" + + " diagnostic:\n" + + " files: true\n"; + + OpenTelemetrySdk sdk = + DeclarativeConfiguration.parseAndCreate( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + + assertThat(sdk) + .extracting("tracerProvider") + .extracting("delegate") + .extracting("sharedState") + .extracting("activeSpanProcessor") + .extracting("profiler") + .extracting("config") + .extracting("backupDiagnosticFiles") + .isEqualTo(true); + + assertThat(sdk.toString()) + .contains("spanProcessor=io.opentelemetry.contrib.inferredspans.InferredSpansProcessor"); } } From 1c220943deeb4431b127e7dff30a256e85fd2b11 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 10:49:17 +0200 Subject: [PATCH 16/41] baggage processor --- baggage-processor/build.gradle.kts | 6 +++ .../BaggageLogRecordComponentProvider.java | 33 +++++++++++++++ .../processor/BaggageLogRecordProcessor.java | 12 +++++- .../processor/BaggageProcessorCustomizer.java | 41 ++++++++++++------- .../BaggageSpanComponentProvider.java | 33 +++++++++++++++ .../processor/BaggageSpanProcessor.java | 12 +++++- ...re.spi.AutoConfigurationCustomizerProvider | 1 - 7 files changed, 121 insertions(+), 17 deletions(-) create mode 100644 baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java create mode 100644 baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java delete mode 100644 baggage-processor/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider diff --git a/baggage-processor/build.gradle.kts b/baggage-processor/build.gradle.kts index 017158399..dac7f8cd0 100644 --- a/baggage-processor/build.gradle.kts +++ b/baggage-processor/build.gradle.kts @@ -8,11 +8,17 @@ description = "OpenTelemetry Baggage Span Processor" otelJava.moduleName.set("io.opentelemetry.contrib.baggage.processor") dependencies { + implementation(project(":declarative-config-bridge")) + + annotationProcessor("com.google.auto.service:auto-service") + compileOnly("com.google.auto.service:auto-service-annotations") api("io.opentelemetry:opentelemetry-api") api("io.opentelemetry:opentelemetry-sdk") implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") testImplementation("org.mockito:mockito-inline") testImplementation("com.google.guava:guava") diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java new file mode 100644 index 000000000..3adaf9ff8 --- /dev/null +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.baggage.processor; + +import com.google.auto.service.AutoService; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.logs.LogRecordProcessor; +import java.util.Collections; + +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class BaggageLogRecordComponentProvider implements ComponentProvider { + @Override + public String getName() { + return "baggage"; + } + + @Override + public LogRecordProcessor create(DeclarativeConfigProperties config) { + return BaggageProcessorCustomizer.createBaggageLogRecordProcessor(ConfigPropertiesUtil.resolveConfig( + config, Collections.singletonMap(BaggageProcessorCustomizer.LOG_PREFIX, ""))); + } + + @Override + public Class getType() { + return LogRecordProcessor.class; + } +} diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java index 4e8c91505..79fcbc313 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java @@ -23,17 +23,23 @@ public class BaggageLogRecordProcessor implements LogRecordProcessor { * created log record. */ public static BaggageLogRecordProcessor allowAllBaggageKeys() { - return new BaggageLogRecordProcessor(baggageKey -> true); + return new BaggageLogRecordProcessor(baggageKey -> true, false); } private final Predicate baggageKeyPredicate; + private boolean empty; /** * Creates a new {@link BaggageLogRecordProcessor} that copies only baggage entries with keys that * pass the provided filter into the newly created log record. */ public BaggageLogRecordProcessor(Predicate baggageKeyPredicate) { + this(baggageKeyPredicate, false); // we don't know if the predicate matches any keys + } + + BaggageLogRecordProcessor(Predicate baggageKeyPredicate, boolean empty) { this.baggageKeyPredicate = baggageKeyPredicate; + this.empty = empty; } @Override @@ -46,4 +52,8 @@ public void onEmit(Context context, ReadWriteLogRecord logRecord) { } }); } + + boolean isEmpty() { + return empty; + } } diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java index da35512a3..b7dad1baf 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java @@ -5,6 +5,7 @@ package io.opentelemetry.contrib.baggage.processor; +import com.google.auto.service.AutoService; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -12,7 +13,11 @@ import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import java.util.List; +@AutoService(AutoConfigurationCustomizerProvider.class) public class BaggageProcessorCustomizer implements AutoConfigurationCustomizerProvider { + static final String SPAN_PREFIX = "otel.java.experimental.span-attributes."; + static final String LOG_PREFIX = "otel.java.experimental.log-attributes."; + @Override public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { autoConfigurationCustomizer @@ -30,39 +35,47 @@ public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { private static void addSpanProcessor( SdkTracerProviderBuilder sdkTracerProviderBuilder, ConfigProperties config) { - List keys = - config.getList("otel.java.experimental.span-attributes.copy-from-baggage.include"); - - if (keys.isEmpty()) { + BaggageSpanProcessor processor = createBaggageSpanProcessor(config); + if (processor.isEmpty()) { return; } + sdkTracerProviderBuilder.addSpanProcessor(processor); + } - sdkTracerProviderBuilder.addSpanProcessor(createBaggageSpanProcessor(keys)); + static BaggageSpanProcessor createBaggageSpanProcessor(ConfigProperties config) { + return createBaggageSpanProcessor( + config.getList(SPAN_PREFIX + "copy-from-baggage.include")); } static BaggageSpanProcessor createBaggageSpanProcessor(List keys) { - if (keys.size() == 1 && keys.get(0).equals("*")) { + if (matchAll(keys)) { return BaggageSpanProcessor.allowAllBaggageKeys(); } - return new BaggageSpanProcessor(keys::contains); + return new BaggageSpanProcessor(keys::contains, keys.isEmpty()); } private static void addLogRecordProcessor( SdkLoggerProviderBuilder sdkLoggerProviderBuilder, ConfigProperties config) { - List keys = - config.getList("otel.java.experimental.log-attributes.copy-from-baggage.include"); - - if (keys.isEmpty()) { + BaggageLogRecordProcessor processor = createBaggageLogRecordProcessor(config); + if (processor.isEmpty()) { return; } + sdkLoggerProviderBuilder.addLogRecordProcessor(processor); + } - sdkLoggerProviderBuilder.addLogRecordProcessor(createBaggageLogRecordProcessor(keys)); + static BaggageLogRecordProcessor createBaggageLogRecordProcessor(ConfigProperties config) { + return createBaggageLogRecordProcessor( + config.getList(LOG_PREFIX + "copy-from-baggage.include")); } static BaggageLogRecordProcessor createBaggageLogRecordProcessor(List keys) { - if (keys.size() == 1 && keys.get(0).equals("*")) { + if (matchAll(keys)) { return BaggageLogRecordProcessor.allowAllBaggageKeys(); } - return new BaggageLogRecordProcessor(keys::contains); + return new BaggageLogRecordProcessor(keys::contains, keys.isEmpty()); + } + + private static boolean matchAll(List keys) { + return keys.size() == 1 && keys.get(0).equals("*"); } } diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java new file mode 100644 index 000000000..c0ae434c3 --- /dev/null +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.baggage.processor; + +import com.google.auto.service.AutoService; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.trace.SpanProcessor; +import java.util.Collections; + +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class BaggageSpanComponentProvider implements ComponentProvider { + @Override + public String getName() { + return "baggage"; + } + + @Override + public SpanProcessor create(DeclarativeConfigProperties config) { + return BaggageProcessorCustomizer.createBaggageSpanProcessor(ConfigPropertiesUtil.resolveConfig( + config, Collections.singletonMap(BaggageProcessorCustomizer.SPAN_PREFIX, ""))); + } + + @Override + public Class getType() { + return SpanProcessor.class; + } +} diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java index 5f0f53d03..e9c4798fc 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java @@ -18,13 +18,19 @@ */ public class BaggageSpanProcessor implements SpanProcessor { private final Predicate baggageKeyPredicate; + private boolean empty; /** * Creates a new {@link BaggageSpanProcessor} that copies only baggage entries with keys that pass * the provided filter into the newly created {@link io.opentelemetry.api.trace.Span}. */ public BaggageSpanProcessor(Predicate baggageKeyPredicate) { + this(baggageKeyPredicate, false); // we don't know if the predicate matches any keys + } + + BaggageSpanProcessor(Predicate baggageKeyPredicate, boolean empty) { this.baggageKeyPredicate = baggageKeyPredicate; + this.empty = empty; } /** @@ -32,7 +38,7 @@ public BaggageSpanProcessor(Predicate baggageKeyPredicate) { * created {@link io.opentelemetry.api.trace.Span}. */ public static BaggageSpanProcessor allowAllBaggageKeys() { - return new BaggageSpanProcessor(baggageKey -> true); + return new BaggageSpanProcessor(baggageKey -> true, false); } @Override @@ -58,4 +64,8 @@ public void onEnd(ReadableSpan span) {} public boolean isEndRequired() { return false; } + + boolean isEmpty() { + return empty; + } } diff --git a/baggage-processor/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider b/baggage-processor/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider deleted file mode 100644 index 8eb4afb06..000000000 --- a/baggage-processor/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider +++ /dev/null @@ -1 +0,0 @@ -io.opentelemetry.contrib.baggage.processor.BaggageProcessorCustomizer From d2279bc6d5086aa09a7b9c8678dafa1b99fbc753 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 10:55:11 +0200 Subject: [PATCH 17/41] format --- .../baggage/processor/BaggageLogRecordComponentProvider.java | 5 +++-- .../baggage/processor/BaggageProcessorCustomizer.java | 3 +-- .../baggage/processor/BaggageSpanComponentProvider.java | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java index 3adaf9ff8..b50b51572 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java @@ -22,8 +22,9 @@ public String getName() { @Override public LogRecordProcessor create(DeclarativeConfigProperties config) { - return BaggageProcessorCustomizer.createBaggageLogRecordProcessor(ConfigPropertiesUtil.resolveConfig( - config, Collections.singletonMap(BaggageProcessorCustomizer.LOG_PREFIX, ""))); + return BaggageProcessorCustomizer.createBaggageLogRecordProcessor( + ConfigPropertiesUtil.resolveConfig( + config, Collections.singletonMap(BaggageProcessorCustomizer.LOG_PREFIX, ""))); } @Override diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java index b7dad1baf..effcab6e2 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java @@ -43,8 +43,7 @@ private static void addSpanProcessor( } static BaggageSpanProcessor createBaggageSpanProcessor(ConfigProperties config) { - return createBaggageSpanProcessor( - config.getList(SPAN_PREFIX + "copy-from-baggage.include")); + return createBaggageSpanProcessor(config.getList(SPAN_PREFIX + "copy-from-baggage.include")); } static BaggageSpanProcessor createBaggageSpanProcessor(List keys) { diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java index c0ae434c3..e37251bb9 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java @@ -22,8 +22,9 @@ public String getName() { @Override public SpanProcessor create(DeclarativeConfigProperties config) { - return BaggageProcessorCustomizer.createBaggageSpanProcessor(ConfigPropertiesUtil.resolveConfig( - config, Collections.singletonMap(BaggageProcessorCustomizer.SPAN_PREFIX, ""))); + return BaggageProcessorCustomizer.createBaggageSpanProcessor( + ConfigPropertiesUtil.resolveConfig( + config, Collections.singletonMap(BaggageProcessorCustomizer.SPAN_PREFIX, ""))); } @Override From 63d7c8cb80b39fefc4f2790d202fc4f8508f3e0a Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 10:55:17 +0200 Subject: [PATCH 18/41] format --- .../inferredspans/InferredSpansCustomizerProviderTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java index cca693e42..20685cbeb 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java @@ -5,14 +5,13 @@ package io.opentelemetry.contrib.inferredspans; +import static org.assertj.core.api.Assertions.assertThat; + import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; -import org.junit.jupiter.api.Test; - import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; - -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; class InferredSpansCustomizerProviderTest { From 402d3057703f0aadf0788df50562f6e7414d9b11 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 11:09:19 +0200 Subject: [PATCH 19/41] stack trace span processor --- .../processor/BaggageLogRecordProcessor.java | 12 +------ .../processor/BaggageProcessorCustomizer.java | 29 ++++++++++------ .../processor/BaggageSpanProcessor.java | 12 +------ span-stacktrace/build.gradle.kts | 4 +++ .../stacktrace/StackTraceAutoConfig.java | 17 +++++----- .../StackTraceComponentProvider.java | 34 +++++++++++++++++++ 6 files changed, 67 insertions(+), 41 deletions(-) create mode 100644 span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java index 79fcbc313..4e8c91505 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java @@ -23,23 +23,17 @@ public class BaggageLogRecordProcessor implements LogRecordProcessor { * created log record. */ public static BaggageLogRecordProcessor allowAllBaggageKeys() { - return new BaggageLogRecordProcessor(baggageKey -> true, false); + return new BaggageLogRecordProcessor(baggageKey -> true); } private final Predicate baggageKeyPredicate; - private boolean empty; /** * Creates a new {@link BaggageLogRecordProcessor} that copies only baggage entries with keys that * pass the provided filter into the newly created log record. */ public BaggageLogRecordProcessor(Predicate baggageKeyPredicate) { - this(baggageKeyPredicate, false); // we don't know if the predicate matches any keys - } - - BaggageLogRecordProcessor(Predicate baggageKeyPredicate, boolean empty) { this.baggageKeyPredicate = baggageKeyPredicate; - this.empty = empty; } @Override @@ -52,8 +46,4 @@ public void onEmit(Context context, ReadWriteLogRecord logRecord) { } }); } - - boolean isEmpty() { - return empty; - } } diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java index effcab6e2..b3ae3ee32 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java @@ -35,43 +35,50 @@ public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { private static void addSpanProcessor( SdkTracerProviderBuilder sdkTracerProviderBuilder, ConfigProperties config) { - BaggageSpanProcessor processor = createBaggageSpanProcessor(config); - if (processor.isEmpty()) { + if (spanKeys(config).isEmpty()) { return; } - sdkTracerProviderBuilder.addSpanProcessor(processor); + + sdkTracerProviderBuilder.addSpanProcessor(createBaggageSpanProcessor(config)); } static BaggageSpanProcessor createBaggageSpanProcessor(ConfigProperties config) { - return createBaggageSpanProcessor(config.getList(SPAN_PREFIX + "copy-from-baggage.include")); + return createBaggageSpanProcessor(spanKeys(config)); + } + + static List spanKeys(ConfigProperties config) { + return config.getList(SPAN_PREFIX + "copy-from-baggage.include"); } static BaggageSpanProcessor createBaggageSpanProcessor(List keys) { if (matchAll(keys)) { return BaggageSpanProcessor.allowAllBaggageKeys(); } - return new BaggageSpanProcessor(keys::contains, keys.isEmpty()); + return new BaggageSpanProcessor(keys::contains); } private static void addLogRecordProcessor( SdkLoggerProviderBuilder sdkLoggerProviderBuilder, ConfigProperties config) { - BaggageLogRecordProcessor processor = createBaggageLogRecordProcessor(config); - if (processor.isEmpty()) { + if (logKeys(config).isEmpty()) { return; } - sdkLoggerProviderBuilder.addLogRecordProcessor(processor); + + sdkLoggerProviderBuilder.addLogRecordProcessor(createBaggageLogRecordProcessor(config)); } static BaggageLogRecordProcessor createBaggageLogRecordProcessor(ConfigProperties config) { - return createBaggageLogRecordProcessor( - config.getList(LOG_PREFIX + "copy-from-baggage.include")); + return createBaggageLogRecordProcessor(logKeys(config)); + } + + static List logKeys(ConfigProperties config) { + return config.getList(LOG_PREFIX + "copy-from-baggage.include"); } static BaggageLogRecordProcessor createBaggageLogRecordProcessor(List keys) { if (matchAll(keys)) { return BaggageLogRecordProcessor.allowAllBaggageKeys(); } - return new BaggageLogRecordProcessor(keys::contains, keys.isEmpty()); + return new BaggageLogRecordProcessor(keys::contains); } private static boolean matchAll(List keys) { diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java index e9c4798fc..5f0f53d03 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java @@ -18,19 +18,13 @@ */ public class BaggageSpanProcessor implements SpanProcessor { private final Predicate baggageKeyPredicate; - private boolean empty; /** * Creates a new {@link BaggageSpanProcessor} that copies only baggage entries with keys that pass * the provided filter into the newly created {@link io.opentelemetry.api.trace.Span}. */ public BaggageSpanProcessor(Predicate baggageKeyPredicate) { - this(baggageKeyPredicate, false); // we don't know if the predicate matches any keys - } - - BaggageSpanProcessor(Predicate baggageKeyPredicate, boolean empty) { this.baggageKeyPredicate = baggageKeyPredicate; - this.empty = empty; } /** @@ -38,7 +32,7 @@ public BaggageSpanProcessor(Predicate baggageKeyPredicate) { * created {@link io.opentelemetry.api.trace.Span}. */ public static BaggageSpanProcessor allowAllBaggageKeys() { - return new BaggageSpanProcessor(baggageKey -> true, false); + return new BaggageSpanProcessor(baggageKey -> true); } @Override @@ -64,8 +58,4 @@ public void onEnd(ReadableSpan span) {} public boolean isEndRequired() { return false; } - - boolean isEmpty() { - return empty; - } } diff --git a/span-stacktrace/build.gradle.kts b/span-stacktrace/build.gradle.kts index 4033b0177..a9fa79e77 100644 --- a/span-stacktrace/build.gradle.kts +++ b/span-stacktrace/build.gradle.kts @@ -7,6 +7,8 @@ description = "OpenTelemetry Java span stacktrace capture module" otelJava.moduleName.set("io.opentelemetry.contrib.stacktrace") dependencies { + implementation(project(":declarative-config-bridge")) + annotationProcessor("com.google.auto.service:auto-service") compileOnly("com.google.auto.service:auto-service-annotations") @@ -15,8 +17,10 @@ dependencies { compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") compileOnly("io.opentelemetry.semconv:opentelemetry-semconv") testImplementation("io.opentelemetry.semconv:opentelemetry-semconv") diff --git a/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceAutoConfig.java b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceAutoConfig.java index 2315d2a10..189934689 100644 --- a/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceAutoConfig.java +++ b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceAutoConfig.java @@ -23,25 +23,26 @@ public class StackTraceAutoConfig implements AutoConfigurationCustomizerProvider private static final Logger log = Logger.getLogger(StackTraceAutoConfig.class.getName()); - private static final String CONFIG_MIN_DURATION = - "otel.java.experimental.span-stacktrace.min.duration"; + static final String PREFIX = "otel.java.experimental.span-stacktrace."; + private static final String CONFIG_MIN_DURATION = PREFIX + "min.duration"; private static final Duration CONFIG_MIN_DURATION_DEFAULT = Duration.ofMillis(5); - - private static final String CONFIG_FILTER = "otel.java.experimental.span-stacktrace.filter"; + private static final String CONFIG_FILTER = PREFIX + "filter"; @Override public void customize(AutoConfigurationCustomizer config) { config.addTracerProviderCustomizer( (providerBuilder, properties) -> { - long minDuration = getMinDuration(properties); - if (minDuration >= 0) { - Predicate filter = getFilterPredicate(properties); - providerBuilder.addSpanProcessor(new StackTraceSpanProcessor(minDuration, filter)); + if (getMinDuration(properties) >= 0) { + providerBuilder.addSpanProcessor(create(properties)); } return providerBuilder; }); } + static StackTraceSpanProcessor create(ConfigProperties properties) { + return new StackTraceSpanProcessor(getMinDuration(properties), getFilterPredicate(properties)); + } + // package-private for testing static long getMinDuration(ConfigProperties properties) { long minDuration = diff --git a/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java new file mode 100644 index 000000000..5606a53a3 --- /dev/null +++ b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.stacktrace; + +import com.google.auto.service.AutoService; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.trace.SpanProcessor; +import java.util.Collections; + +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class StackTraceComponentProvider implements ComponentProvider { + @Override + public String getName() { + return "stacktrace"; + } + + @Override + public SpanProcessor create(DeclarativeConfigProperties config) { + return StackTraceAutoConfig.create( + ConfigPropertiesUtil.resolveConfig( + config, Collections.singletonMap(StackTraceAutoConfig.PREFIX, ""))); + } + + @Override + public Class getType() { + return SpanProcessor.class; + } +} From e5355f5650d26042d109caf5138c183c8a7ab041 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 11:12:57 +0200 Subject: [PATCH 20/41] stack trace span processor --- .../processor/BaggageProcessorCustomizer.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java index b3ae3ee32..3dbf017b4 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java @@ -46,10 +46,6 @@ static BaggageSpanProcessor createBaggageSpanProcessor(ConfigProperties config) return createBaggageSpanProcessor(spanKeys(config)); } - static List spanKeys(ConfigProperties config) { - return config.getList(SPAN_PREFIX + "copy-from-baggage.include"); - } - static BaggageSpanProcessor createBaggageSpanProcessor(List keys) { if (matchAll(keys)) { return BaggageSpanProcessor.allowAllBaggageKeys(); @@ -57,6 +53,10 @@ static BaggageSpanProcessor createBaggageSpanProcessor(List keys) { return new BaggageSpanProcessor(keys::contains); } + static List spanKeys(ConfigProperties config) { + return config.getList(SPAN_PREFIX + "copy-from-baggage.include"); + } + private static void addLogRecordProcessor( SdkLoggerProviderBuilder sdkLoggerProviderBuilder, ConfigProperties config) { if (logKeys(config).isEmpty()) { @@ -70,10 +70,6 @@ static BaggageLogRecordProcessor createBaggageLogRecordProcessor(ConfigPropertie return createBaggageLogRecordProcessor(logKeys(config)); } - static List logKeys(ConfigProperties config) { - return config.getList(LOG_PREFIX + "copy-from-baggage.include"); - } - static BaggageLogRecordProcessor createBaggageLogRecordProcessor(List keys) { if (matchAll(keys)) { return BaggageLogRecordProcessor.allowAllBaggageKeys(); @@ -81,6 +77,10 @@ static BaggageLogRecordProcessor createBaggageLogRecordProcessor(List ke return new BaggageLogRecordProcessor(keys::contains); } + static List logKeys(ConfigProperties config) { + return config.getList(LOG_PREFIX + "copy-from-baggage.include"); + } + private static boolean matchAll(List keys) { return keys.size() == 1 && keys.get(0).equals("*"); } From c6d9eeec76acdf6b4ab0a290ff7f741b8ba01ed1 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 11:16:37 +0200 Subject: [PATCH 21/41] fix --- baggage-processor/build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baggage-processor/build.gradle.kts b/baggage-processor/build.gradle.kts index dac7f8cd0..af21261aa 100644 --- a/baggage-processor/build.gradle.kts +++ b/baggage-processor/build.gradle.kts @@ -17,6 +17,8 @@ dependencies { implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") + testAnnotationProcessor("com.google.auto.service:auto-service") + testCompileOnly("com.google.auto.service:auto-service-annotations") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") From 67adb3ba194aa6992969d25272f607ed8fb7048a Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 12:38:52 +0200 Subject: [PATCH 22/41] fix --- .../processor/BaggageLogRecordComponentProvider.java | 2 +- .../baggage/processor/BaggageProcessorCustomizer.java | 6 ++---- .../baggage/processor/BaggageSpanComponentProvider.java | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java index b50b51572..db309e726 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java @@ -24,7 +24,7 @@ public String getName() { public LogRecordProcessor create(DeclarativeConfigProperties config) { return BaggageProcessorCustomizer.createBaggageLogRecordProcessor( ConfigPropertiesUtil.resolveConfig( - config, Collections.singletonMap(BaggageProcessorCustomizer.LOG_PREFIX, ""))); + config, Collections.singletonMap("otel.java.experimental.log-attributes.", ""))); } @Override diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java index 3dbf017b4..08a7fcf61 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java @@ -15,8 +15,6 @@ @AutoService(AutoConfigurationCustomizerProvider.class) public class BaggageProcessorCustomizer implements AutoConfigurationCustomizerProvider { - static final String SPAN_PREFIX = "otel.java.experimental.span-attributes."; - static final String LOG_PREFIX = "otel.java.experimental.log-attributes."; @Override public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { @@ -54,7 +52,7 @@ static BaggageSpanProcessor createBaggageSpanProcessor(List keys) { } static List spanKeys(ConfigProperties config) { - return config.getList(SPAN_PREFIX + "copy-from-baggage.include"); + return config.getList("otel.java.experimental.span-attributes.copy-from-baggage.include"); } private static void addLogRecordProcessor( @@ -78,7 +76,7 @@ static BaggageLogRecordProcessor createBaggageLogRecordProcessor(List ke } static List logKeys(ConfigProperties config) { - return config.getList(LOG_PREFIX + "copy-from-baggage.include"); + return config.getList("otel.java.experimental.log-attributes.copy-from-baggage.include"); } private static boolean matchAll(List keys) { diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java index e37251bb9..69227802f 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java @@ -24,7 +24,7 @@ public String getName() { public SpanProcessor create(DeclarativeConfigProperties config) { return BaggageProcessorCustomizer.createBaggageSpanProcessor( ConfigPropertiesUtil.resolveConfig( - config, Collections.singletonMap(BaggageProcessorCustomizer.SPAN_PREFIX, ""))); + config, Collections.singletonMap("otel.java.experimental.span-attributes.", ""))); } @Override From 6daffa5f422476b342d73cdd741722ca658d90da Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 13:36:43 +0200 Subject: [PATCH 23/41] fix --- .../processor/BaggageProcessorCustomizerTest.java | 4 ++-- .../InferredSpansCustomizerProviderTest.java | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java b/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java index bfa8835ae..f30371ff5 100644 --- a/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java +++ b/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java @@ -103,9 +103,9 @@ private static OpenTelemetrySdk getOpenTelemetrySdk( // We set the export interval of the spans to 10 ms. The default value is 5 // seconds. "otel.bsp.schedule.delay", // span exporter - "10", + "100", "otel.blrp.schedule.delay", // log exporter - "10", + "100", "otel.traces.exporter", MEMORY_EXPORTER, "otel.metrics.exporter", diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java index 20685cbeb..ea1665d70 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java @@ -7,14 +7,25 @@ import static org.assertj.core.api.Assertions.assertThat; +import io.opentelemetry.contrib.inferredspans.internal.ProfilingActivationListener; +import io.opentelemetry.contrib.inferredspans.internal.util.OtelReflectionUtils; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class InferredSpansCustomizerProviderTest { + @BeforeEach + @AfterEach + public void resetGlobalOtel() { + ProfilingActivationListener.ensureInitialized(); + OtelReflectionUtils.shutdownAndResetGlobalOtel(); + } + @Test void declarativeConfig() { String yaml = @@ -39,8 +50,5 @@ void declarativeConfig() { .extracting("config") .extracting("backupDiagnosticFiles") .isEqualTo(true); - - assertThat(sdk.toString()) - .contains("spanProcessor=io.opentelemetry.contrib.inferredspans.InferredSpansProcessor"); } } From 434fb80b185e208fb46819be68ad89658e7f0677 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 14:00:40 +0200 Subject: [PATCH 24/41] make temp dir more reliable --- .../inferredspans/InferredSpansProcessor.java | 3 +- .../internal/SamplingProfiler.java | 10 ++++-- .../internal/SamplingProfilerTest.java | 32 ++++--------------- 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java index 22f59ba53..b96163b48 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java @@ -49,7 +49,8 @@ public class InferredSpansProcessor implements SpanProcessor { boolean startScheduledProfiling, @Nullable File activationEventsFile, @Nullable File jfrFile) { - profiler = new SamplingProfiler(config, clock, this::getTracer, activationEventsFile, jfrFile); + profiler = + new SamplingProfiler(config, clock, this::getTracer, activationEventsFile, jfrFile, null); if (startScheduledProfiling) { profiler.start(); } diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index 61e5f75a7..4bd392210 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -149,6 +149,7 @@ public class SamplingProfiler implements Runnable { private final ProfilingActivationListener activationListener; private final Supplier tracerProvider; + @Nullable private final File tempDir; private final AsyncProfiler profiler; @@ -168,9 +169,11 @@ public SamplingProfiler( SpanAnchoredClock nanoClock, Supplier tracerProvider, @Nullable File activationEventsFile, - @Nullable File jfrFile) { + @Nullable File jfrFile, + @Nullable File tempDir) { this.config = config; this.tracerProvider = tracerProvider; + this.tempDir = tempDir; this.scheduler = Executors.newSingleThreadScheduledExecutor( r -> { @@ -250,12 +253,13 @@ boolean isProfilingActiveOnThread(Thread thread) { private synchronized void createFilesIfRequired() throws IOException { if (jfrFile == null || !jfrFile.exists()) { - jfrFile = File.createTempFile("otel-inferred-traces-", ".jfr"); + jfrFile = File.createTempFile("otel-inferred-traces-", ".jfr", tempDir); jfrFile.deleteOnExit(); canDeleteJfrFile = true; } if (activationEventsFile == null || !activationEventsFile.exists()) { - activationEventsFile = File.createTempFile("otel-inferred-activation-events-", ".bin"); + activationEventsFile = + File.createTempFile("otel-inferred-activation-events-", ".bin", tempDir); activationEventsFile.deleteOnExit(); canDeleteActivationEventsFile = true; } diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java index b97ce8729..ff4a8def5 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java @@ -32,12 +32,12 @@ import java.util.stream.Stream; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledForJreRange; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.JRE; import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.io.TempDir; // async-profiler doesn't work on Windows @DisabledOnOs(OS.WINDOWS) @@ -46,11 +46,7 @@ class SamplingProfilerTest { private ProfilerTestSetup setup; - @BeforeEach - void setup() { - // avoids any test failure to make other tests to fail - getProfilerTempFiles().forEach(SamplingProfilerTest::silentDeleteFile); - } + @TempDir private Path tempDir; @AfterEach void tearDown() { @@ -58,7 +54,6 @@ void tearDown() { setup.close(); setup = null; } - getProfilerTempFiles().forEach(SamplingProfilerTest::silentDeleteFile); } @Test @@ -117,8 +112,8 @@ void shouldNotDeleteProvidedFiles() throws Exception { defaultConfig = ProfilerTestSetup.extractProfilerImpl(profiler1).getConfig(); } - Path tempFile1 = Files.createTempFile("otel-inferred-provided", "test.bin"); - Path tempFile2 = Files.createTempFile("otel-inferred-provided", "test.jfr"); + Path tempFile1 = Files.createTempFile(tempDir, "otel-inferred-provided", "test.bin"); + Path tempFile2 = Files.createTempFile(tempDir, "otel-inferred-provided", "test.jfr"); try (OpenTelemetrySdk sdk = OpenTelemetrySdk.builder().build()) { @@ -128,7 +123,8 @@ void shouldNotDeleteProvidedFiles() throws Exception { new FixedClock(), () -> sdk.getTracer("my-tracer"), tempFile1.toFile(), - tempFile2.toFile()); + tempFile2.toFile(), + tempDir.toFile()); otherProfiler.start(); awaitProfilerStarted(otherProfiler); @@ -333,20 +329,4 @@ private void setupProfiler(Consumer configCustomi configCustomizer.accept(config); }); } - - private static void awaitProfilerStarted(SamplingProfiler profiler) { - // ensure profiler is initialized - await() - .pollDelay(Duration.ofMillis(10)) - .timeout(Duration.ofSeconds(6)) - .until(() -> profiler.getProfilingSessions() > 1); - } - - private static void silentDeleteFile(Path f) { - try { - Files.delete(f); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } } From 9bc8664f95ea0f8fd7ce77b0a4536ab6179cd283 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 14:05:17 +0200 Subject: [PATCH 25/41] make temp dir more reliable --- .../inferredspans/internal/SamplingProfilerTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java index ff4a8def5..1e9d97807 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java @@ -329,4 +329,12 @@ private void setupProfiler(Consumer configCustomi configCustomizer.accept(config); }); } + + private static void awaitProfilerStarted(SamplingProfiler profiler) { + // ensure profiler is initialized + await() + .pollDelay(Duration.ofMillis(10)) + .timeout(Duration.ofSeconds(6)) + .until(() -> profiler.getProfilingSessions() > 1); + } } From d7d49157564c3917d5de61685fbaf0673866817f Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 15 Jul 2025 14:10:12 +0200 Subject: [PATCH 26/41] revert inferred spans (flaky) --- inferred-spans/build.gradle.kts | 4 -- .../InferredSpansAutoConfig.java | 50 ++++++++--------- .../InferredSpansComponentProvider.java | 35 ------------ .../inferredspans/InferredSpansProcessor.java | 3 +- .../internal/SamplingProfiler.java | 10 ++-- .../InferredSpansCustomizerProviderTest.java | 54 ------------------- .../internal/SamplingProfilerTest.java | 24 ++++++--- 7 files changed, 45 insertions(+), 135 deletions(-) delete mode 100644 inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java delete mode 100644 inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java diff --git a/inferred-spans/build.gradle.kts b/inferred-spans/build.gradle.kts index bc89d6da9..98d5e33a3 100644 --- a/inferred-spans/build.gradle.kts +++ b/inferred-spans/build.gradle.kts @@ -9,13 +9,10 @@ description = "OpenTelemetry Java profiling based inferred spans module" otelJava.moduleName.set("io.opentelemetry.contrib.inferredspans") dependencies { - implementation(project(":declarative-config-bridge")) - annotationProcessor("com.google.auto.service:auto-service") compileOnly("com.google.auto.service:auto-service-annotations") compileOnly("io.opentelemetry:opentelemetry-sdk") compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") - compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") compileOnly("io.opentelemetry.semconv:opentelemetry-semconv") implementation("com.lmax:disruptor") implementation("org.jctools:jctools-core") @@ -28,7 +25,6 @@ dependencies { testImplementation("io.opentelemetry.semconv:opentelemetry-semconv") testImplementation("io.opentelemetry:opentelemetry-sdk") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") - testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") testImplementation("io.opentelemetry:opentelemetry-api-incubator") testImplementation("io.opentelemetry:opentelemetry-exporter-logging") diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java index f944841d7..9c8118ec5 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansAutoConfig.java @@ -11,7 +11,6 @@ import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import io.opentelemetry.sdk.trace.SpanProcessor; import java.time.Duration; import java.util.Arrays; import java.util.List; @@ -46,7 +45,29 @@ public void customize(AutoConfigurationCustomizer config) { config.addTracerProviderCustomizer( (providerBuilder, properties) -> { if (properties.getBoolean(ENABLED_OPTION, false)) { - providerBuilder.addSpanProcessor(create(properties)); + InferredSpansProcessorBuilder builder = InferredSpansProcessor.builder(); + + PropertiesApplier applier = new PropertiesApplier(properties); + + applier.applyBool(LOGGING_OPTION, builder::profilerLoggingEnabled); + applier.applyBool(DIAGNOSTIC_FILES_OPTION, builder::backupDiagnosticFiles); + applier.applyInt(SAFEMODE_OPTION, builder::asyncProfilerSafeMode); + applier.applyBool(POSTPROCESSING_OPTION, builder::postProcessingEnabled); + applier.applyDuration(SAMPLING_INTERVAL_OPTION, builder::samplingInterval); + applier.applyDuration(MIN_DURATION_OPTION, builder::inferredSpansMinDuration); + applier.applyWildcards(INCLUDED_CLASSES_OPTION, builder::includedClasses); + applier.applyWildcards(EXCLUDED_CLASSES_OPTION, builder::excludedClasses); + applier.applyDuration(INTERVAL_OPTION, builder::profilerInterval); + applier.applyDuration(DURATION_OPTION, builder::profilingDuration); + applier.applyString(LIB_DIRECTORY_OPTION, builder::profilerLibDirectory); + + String parentOverrideHandlerName = properties.getString(PARENT_OVERRIDE_HANDLER_OPTION); + if (parentOverrideHandlerName != null && !parentOverrideHandlerName.isEmpty()) { + builder.parentOverrideHandler( + constructParentOverrideHandler(parentOverrideHandlerName)); + } + + providerBuilder.addSpanProcessor(builder.build()); } else { log.finest( "Not enabling inferred spans processor because " + ENABLED_OPTION + " is not set"); @@ -55,31 +76,6 @@ public void customize(AutoConfigurationCustomizer config) { }); } - static SpanProcessor create(ConfigProperties properties) { - InferredSpansProcessorBuilder builder = InferredSpansProcessor.builder(); - - PropertiesApplier applier = new PropertiesApplier(properties); - - applier.applyBool(LOGGING_OPTION, builder::profilerLoggingEnabled); - applier.applyBool(DIAGNOSTIC_FILES_OPTION, builder::backupDiagnosticFiles); - applier.applyInt(SAFEMODE_OPTION, builder::asyncProfilerSafeMode); - applier.applyBool(POSTPROCESSING_OPTION, builder::postProcessingEnabled); - applier.applyDuration(SAMPLING_INTERVAL_OPTION, builder::samplingInterval); - applier.applyDuration(MIN_DURATION_OPTION, builder::inferredSpansMinDuration); - applier.applyWildcards(INCLUDED_CLASSES_OPTION, builder::includedClasses); - applier.applyWildcards(EXCLUDED_CLASSES_OPTION, builder::excludedClasses); - applier.applyDuration(INTERVAL_OPTION, builder::profilerInterval); - applier.applyDuration(DURATION_OPTION, builder::profilingDuration); - applier.applyString(LIB_DIRECTORY_OPTION, builder::profilerLibDirectory); - - String parentOverrideHandlerName = properties.getString(PARENT_OVERRIDE_HANDLER_OPTION); - if (parentOverrideHandlerName != null && !parentOverrideHandlerName.isEmpty()) { - builder.parentOverrideHandler(constructParentOverrideHandler(parentOverrideHandlerName)); - } - - return builder.build(); - } - @SuppressWarnings("unchecked") private static BiConsumer constructParentOverrideHandler(String name) { try { diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java deleted file mode 100644 index 21101d639..000000000 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansComponentProvider.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.inferredspans; - -import com.google.auto.service.AutoService; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.trace.SpanProcessor; -import java.util.Collections; - -@SuppressWarnings("rawtypes") -@AutoService(ComponentProvider.class) -public class InferredSpansComponentProvider implements ComponentProvider { - - @Override - public String getName() { - return "inferred_spans"; - } - - @Override - public SpanProcessor create(DeclarativeConfigProperties config) { - return InferredSpansAutoConfig.create( - ConfigPropertiesUtil.resolveConfig( - config, Collections.singletonMap("otel.inferred.spans.", ""))); - } - - @Override - public Class getType() { - return SpanProcessor.class; - } -} diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java index b96163b48..22f59ba53 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java @@ -49,8 +49,7 @@ public class InferredSpansProcessor implements SpanProcessor { boolean startScheduledProfiling, @Nullable File activationEventsFile, @Nullable File jfrFile) { - profiler = - new SamplingProfiler(config, clock, this::getTracer, activationEventsFile, jfrFile, null); + profiler = new SamplingProfiler(config, clock, this::getTracer, activationEventsFile, jfrFile); if (startScheduledProfiling) { profiler.start(); } diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index 4bd392210..61e5f75a7 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -149,7 +149,6 @@ public class SamplingProfiler implements Runnable { private final ProfilingActivationListener activationListener; private final Supplier tracerProvider; - @Nullable private final File tempDir; private final AsyncProfiler profiler; @@ -169,11 +168,9 @@ public SamplingProfiler( SpanAnchoredClock nanoClock, Supplier tracerProvider, @Nullable File activationEventsFile, - @Nullable File jfrFile, - @Nullable File tempDir) { + @Nullable File jfrFile) { this.config = config; this.tracerProvider = tracerProvider; - this.tempDir = tempDir; this.scheduler = Executors.newSingleThreadScheduledExecutor( r -> { @@ -253,13 +250,12 @@ boolean isProfilingActiveOnThread(Thread thread) { private synchronized void createFilesIfRequired() throws IOException { if (jfrFile == null || !jfrFile.exists()) { - jfrFile = File.createTempFile("otel-inferred-traces-", ".jfr", tempDir); + jfrFile = File.createTempFile("otel-inferred-traces-", ".jfr"); jfrFile.deleteOnExit(); canDeleteJfrFile = true; } if (activationEventsFile == null || !activationEventsFile.exists()) { - activationEventsFile = - File.createTempFile("otel-inferred-activation-events-", ".bin", tempDir); + activationEventsFile = File.createTempFile("otel-inferred-activation-events-", ".bin"); activationEventsFile.deleteOnExit(); canDeleteActivationEventsFile = true; } diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java deleted file mode 100644 index ea1665d70..000000000 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansCustomizerProviderTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.inferredspans; - -import static org.assertj.core.api.Assertions.assertThat; - -import io.opentelemetry.contrib.inferredspans.internal.ProfilingActivationListener; -import io.opentelemetry.contrib.inferredspans.internal.util.OtelReflectionUtils; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class InferredSpansCustomizerProviderTest { - - @BeforeEach - @AfterEach - public void resetGlobalOtel() { - ProfilingActivationListener.ensureInitialized(); - OtelReflectionUtils.shutdownAndResetGlobalOtel(); - } - - @Test - void declarativeConfig() { - String yaml = - "file_format: 0.4\n" - + "tracer_provider:\n" - + " processors:\n" - + " - inferred_spans:\n" - + " backup:\n" - + " diagnostic:\n" - + " files: true\n"; - - OpenTelemetrySdk sdk = - DeclarativeConfiguration.parseAndCreate( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); - - assertThat(sdk) - .extracting("tracerProvider") - .extracting("delegate") - .extracting("sharedState") - .extracting("activeSpanProcessor") - .extracting("profiler") - .extracting("config") - .extracting("backupDiagnosticFiles") - .isEqualTo(true); - } -} diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java index 1e9d97807..b97ce8729 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java @@ -32,12 +32,12 @@ import java.util.stream.Stream; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledForJreRange; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.JRE; import org.junit.jupiter.api.condition.OS; -import org.junit.jupiter.api.io.TempDir; // async-profiler doesn't work on Windows @DisabledOnOs(OS.WINDOWS) @@ -46,7 +46,11 @@ class SamplingProfilerTest { private ProfilerTestSetup setup; - @TempDir private Path tempDir; + @BeforeEach + void setup() { + // avoids any test failure to make other tests to fail + getProfilerTempFiles().forEach(SamplingProfilerTest::silentDeleteFile); + } @AfterEach void tearDown() { @@ -54,6 +58,7 @@ void tearDown() { setup.close(); setup = null; } + getProfilerTempFiles().forEach(SamplingProfilerTest::silentDeleteFile); } @Test @@ -112,8 +117,8 @@ void shouldNotDeleteProvidedFiles() throws Exception { defaultConfig = ProfilerTestSetup.extractProfilerImpl(profiler1).getConfig(); } - Path tempFile1 = Files.createTempFile(tempDir, "otel-inferred-provided", "test.bin"); - Path tempFile2 = Files.createTempFile(tempDir, "otel-inferred-provided", "test.jfr"); + Path tempFile1 = Files.createTempFile("otel-inferred-provided", "test.bin"); + Path tempFile2 = Files.createTempFile("otel-inferred-provided", "test.jfr"); try (OpenTelemetrySdk sdk = OpenTelemetrySdk.builder().build()) { @@ -123,8 +128,7 @@ void shouldNotDeleteProvidedFiles() throws Exception { new FixedClock(), () -> sdk.getTracer("my-tracer"), tempFile1.toFile(), - tempFile2.toFile(), - tempDir.toFile()); + tempFile2.toFile()); otherProfiler.start(); awaitProfilerStarted(otherProfiler); @@ -337,4 +341,12 @@ private static void awaitProfilerStarted(SamplingProfiler profiler) { .timeout(Duration.ofSeconds(6)) .until(() -> profiler.getProfilingSessions() > 1); } + + private static void silentDeleteFile(Path f) { + try { + Files.delete(f); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } } From 25c42bf955634b1e784aa22cb18ec36aa2151fb8 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 16 Jul 2025 09:13:18 +0200 Subject: [PATCH 27/41] baggage is in a separate PR --- baggage-processor/build.gradle.kts | 8 ---- .../BaggageLogRecordComponentProvider.java | 34 --------------- .../processor/BaggageProcessorCustomizer.java | 41 ++++++------------- .../BaggageSpanComponentProvider.java | 34 --------------- ...re.spi.AutoConfigurationCustomizerProvider | 1 + .../BaggageProcessorCustomizerTest.java | 4 +- 6 files changed, 15 insertions(+), 107 deletions(-) delete mode 100644 baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java delete mode 100644 baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java create mode 100644 baggage-processor/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider diff --git a/baggage-processor/build.gradle.kts b/baggage-processor/build.gradle.kts index af21261aa..017158399 100644 --- a/baggage-processor/build.gradle.kts +++ b/baggage-processor/build.gradle.kts @@ -8,19 +8,11 @@ description = "OpenTelemetry Baggage Span Processor" otelJava.moduleName.set("io.opentelemetry.contrib.baggage.processor") dependencies { - implementation(project(":declarative-config-bridge")) - - annotationProcessor("com.google.auto.service:auto-service") - compileOnly("com.google.auto.service:auto-service-annotations") api("io.opentelemetry:opentelemetry-api") api("io.opentelemetry:opentelemetry-sdk") implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") - compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") - testAnnotationProcessor("com.google.auto.service:auto-service") - testCompileOnly("com.google.auto.service:auto-service-annotations") testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") - testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") testImplementation("org.mockito:mockito-inline") testImplementation("com.google.guava:guava") diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java deleted file mode 100644 index db309e726..000000000 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.baggage.processor; - -import com.google.auto.service.AutoService; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.logs.LogRecordProcessor; -import java.util.Collections; - -@SuppressWarnings("rawtypes") -@AutoService(ComponentProvider.class) -public class BaggageLogRecordComponentProvider implements ComponentProvider { - @Override - public String getName() { - return "baggage"; - } - - @Override - public LogRecordProcessor create(DeclarativeConfigProperties config) { - return BaggageProcessorCustomizer.createBaggageLogRecordProcessor( - ConfigPropertiesUtil.resolveConfig( - config, Collections.singletonMap("otel.java.experimental.log-attributes.", ""))); - } - - @Override - public Class getType() { - return LogRecordProcessor.class; - } -} diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java index 08a7fcf61..da35512a3 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java @@ -5,7 +5,6 @@ package io.opentelemetry.contrib.baggage.processor; -import com.google.auto.service.AutoService; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -13,9 +12,7 @@ import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import java.util.List; -@AutoService(AutoConfigurationCustomizerProvider.class) public class BaggageProcessorCustomizer implements AutoConfigurationCustomizerProvider { - @Override public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { autoConfigurationCustomizer @@ -33,53 +30,39 @@ public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { private static void addSpanProcessor( SdkTracerProviderBuilder sdkTracerProviderBuilder, ConfigProperties config) { - if (spanKeys(config).isEmpty()) { + List keys = + config.getList("otel.java.experimental.span-attributes.copy-from-baggage.include"); + + if (keys.isEmpty()) { return; } - sdkTracerProviderBuilder.addSpanProcessor(createBaggageSpanProcessor(config)); - } - - static BaggageSpanProcessor createBaggageSpanProcessor(ConfigProperties config) { - return createBaggageSpanProcessor(spanKeys(config)); + sdkTracerProviderBuilder.addSpanProcessor(createBaggageSpanProcessor(keys)); } static BaggageSpanProcessor createBaggageSpanProcessor(List keys) { - if (matchAll(keys)) { + if (keys.size() == 1 && keys.get(0).equals("*")) { return BaggageSpanProcessor.allowAllBaggageKeys(); } return new BaggageSpanProcessor(keys::contains); } - static List spanKeys(ConfigProperties config) { - return config.getList("otel.java.experimental.span-attributes.copy-from-baggage.include"); - } - private static void addLogRecordProcessor( SdkLoggerProviderBuilder sdkLoggerProviderBuilder, ConfigProperties config) { - if (logKeys(config).isEmpty()) { + List keys = + config.getList("otel.java.experimental.log-attributes.copy-from-baggage.include"); + + if (keys.isEmpty()) { return; } - sdkLoggerProviderBuilder.addLogRecordProcessor(createBaggageLogRecordProcessor(config)); - } - - static BaggageLogRecordProcessor createBaggageLogRecordProcessor(ConfigProperties config) { - return createBaggageLogRecordProcessor(logKeys(config)); + sdkLoggerProviderBuilder.addLogRecordProcessor(createBaggageLogRecordProcessor(keys)); } static BaggageLogRecordProcessor createBaggageLogRecordProcessor(List keys) { - if (matchAll(keys)) { + if (keys.size() == 1 && keys.get(0).equals("*")) { return BaggageLogRecordProcessor.allowAllBaggageKeys(); } return new BaggageLogRecordProcessor(keys::contains); } - - static List logKeys(ConfigProperties config) { - return config.getList("otel.java.experimental.log-attributes.copy-from-baggage.include"); - } - - private static boolean matchAll(List keys) { - return keys.size() == 1 && keys.get(0).equals("*"); - } } diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java deleted file mode 100644 index 69227802f..000000000 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.baggage.processor; - -import com.google.auto.service.AutoService; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.trace.SpanProcessor; -import java.util.Collections; - -@SuppressWarnings("rawtypes") -@AutoService(ComponentProvider.class) -public class BaggageSpanComponentProvider implements ComponentProvider { - @Override - public String getName() { - return "baggage"; - } - - @Override - public SpanProcessor create(DeclarativeConfigProperties config) { - return BaggageProcessorCustomizer.createBaggageSpanProcessor( - ConfigPropertiesUtil.resolveConfig( - config, Collections.singletonMap("otel.java.experimental.span-attributes.", ""))); - } - - @Override - public Class getType() { - return SpanProcessor.class; - } -} diff --git a/baggage-processor/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider b/baggage-processor/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider new file mode 100644 index 000000000..8eb4afb06 --- /dev/null +++ b/baggage-processor/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider @@ -0,0 +1 @@ +io.opentelemetry.contrib.baggage.processor.BaggageProcessorCustomizer diff --git a/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java b/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java index f30371ff5..bfa8835ae 100644 --- a/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java +++ b/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java @@ -103,9 +103,9 @@ private static OpenTelemetrySdk getOpenTelemetrySdk( // We set the export interval of the spans to 10 ms. The default value is 5 // seconds. "otel.bsp.schedule.delay", // span exporter - "100", + "10", "otel.blrp.schedule.delay", // log exporter - "100", + "10", "otel.traces.exporter", MEMORY_EXPORTER, "otel.metrics.exporter", From 1aa789c8b34fe99948da89794c4b87c459b8a8c0 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 18 Jul 2025 17:06:44 +0200 Subject: [PATCH 28/41] use unified bridge --- .../autoconfigure/ConfigPropertiesUtil.java | 32 +++---- .../DeclarativeConfigPropertiesBridge.java | 62 +++++++++---- .../sdk/autoconfigure/PropertyTranslator.java | 37 ++++++++ .../PropertyTranslatorBuilder.java | 33 +++++++ ...DeclarativeConfigPropertiesBridgeTest.java | 88 +++++++++---------- .../src/test/resources/config.yaml | 27 ++++++ .../gcp/auth/GcpAuthCustomizerProvider.java | 8 +- .../auth/GcpAuthCustomizerProviderTest.java | 3 +- .../StackTraceComponentProvider.java | 5 +- 9 files changed, 204 insertions(+), 91 deletions(-) create mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslator.java create mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslatorBuilder.java create mode 100644 declarative-config-bridge/src/test/resources/config.yaml diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index 457e49b90..eaf18d584 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -10,13 +10,9 @@ import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; -import java.util.Collections; -import java.util.Map; import javax.annotation.Nullable; -public class ConfigPropertiesUtil { +public final class ConfigPropertiesUtil { private ConfigPropertiesUtil() {} /** Resolve {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ @@ -31,41 +27,35 @@ public static ConfigProperties resolveConfigProperties( AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); if (configProvider != null) { return resolveInstrumentationConfig( - configProvider.getInstrumentationConfig(), Collections.emptyMap()); + configProvider.getInstrumentationConfig(), propertyTranslatorBuilder()); } // Should never happen throw new IllegalStateException( "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); } - public static ConfigProperties resolveModel(OpenTelemetryConfigurationModel model) { - return resolveModel(model, Collections.emptyMap()); - } - - public static ConfigProperties resolveModel( - OpenTelemetryConfigurationModel model, Map translationMap) { - return resolveInstrumentationConfig( - SdkConfigProvider.create(model).getInstrumentationConfig(), translationMap); - } - public static ConfigProperties resolveInstrumentationConfig( @Nullable DeclarativeConfigProperties instrumentationConfig) { - return resolveInstrumentationConfig(instrumentationConfig, Collections.emptyMap()); + return resolveInstrumentationConfig(instrumentationConfig, propertyTranslatorBuilder()); } public static ConfigProperties resolveInstrumentationConfig( @Nullable DeclarativeConfigProperties instrumentationConfig, - Map translationMap) { + PropertyTranslatorBuilder builder) { return DeclarativeConfigPropertiesBridge.fromInstrumentationConfig( - instrumentationConfig, translationMap); + instrumentationConfig, builder.build()); } public static ConfigProperties resolveConfig( - @Nullable DeclarativeConfigProperties config, Map translationMap) { - return DeclarativeConfigPropertiesBridge.create(config, translationMap); + @Nullable DeclarativeConfigProperties config, PropertyTranslatorBuilder builder) { + return DeclarativeConfigPropertiesBridge.create(config, builder.build()); } public static String propertyYamlPath(String propertyName) { return DeclarativeConfigPropertiesBridge.yamlPath(propertyName); } + + public static PropertyTranslatorBuilder propertyTranslatorBuilder() { + return new PropertyTranslatorBuilder(); + } } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index 8acdc32a1..188c4e899 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -50,63 +50,86 @@ final class DeclarativeConfigPropertiesBridge implements ConfigProperties { private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; + private final PropertyTranslator translator; @Nullable private final DeclarativeConfigProperties baseNode; - private final Map translationMap; static DeclarativeConfigPropertiesBridge fromInstrumentationConfig( - @Nullable DeclarativeConfigProperties instrumentationConfig, - Map translationMap) { + @Nullable DeclarativeConfigProperties instrumentationConfig, PropertyTranslator translator) { if (instrumentationConfig == null) { instrumentationConfig = DeclarativeConfigProperties.empty(); } return new DeclarativeConfigPropertiesBridge( - instrumentationConfig.getStructured("java", empty()), translationMap); + instrumentationConfig.getStructured("java", empty()), translator); } static DeclarativeConfigPropertiesBridge create( - @Nullable DeclarativeConfigProperties node, Map translationMap) { - return new DeclarativeConfigPropertiesBridge(node, translationMap); + @Nullable DeclarativeConfigProperties node, PropertyTranslator translator) { + return new DeclarativeConfigPropertiesBridge(node, translator); } private DeclarativeConfigPropertiesBridge( - @Nullable DeclarativeConfigProperties baseNode, Map translationMap) { + @Nullable DeclarativeConfigProperties baseNode, PropertyTranslator translator) { this.baseNode = baseNode; - this.translationMap = translationMap; + this.translator = translator; } @Nullable @Override public String getString(String propertyName) { + Object value = translator.get(propertyName); + if (value != null) { + return value.toString(); + } return getPropertyValue(propertyName, DeclarativeConfigProperties::getString); } @Nullable @Override public Boolean getBoolean(String propertyName) { + Object value = translator.get(propertyName); + if (value != null) { + return (Boolean) value; + } return getPropertyValue(propertyName, DeclarativeConfigProperties::getBoolean); } @Nullable @Override public Integer getInt(String propertyName) { + Object value = translator.get(propertyName); + if (value != null) { + return (Integer) value; + } return getPropertyValue(propertyName, DeclarativeConfigProperties::getInt); } @Nullable @Override public Long getLong(String propertyName) { + Object value = translator.get(propertyName); + if (value != null) { + return (Long) value; + } return getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); } @Nullable @Override public Double getDouble(String propertyName) { + Object value = translator.get(propertyName); + if (value != null) { + return (Double) value; + } return getPropertyValue(propertyName, DeclarativeConfigProperties::getDouble); } @Nullable @Override public Duration getDuration(String propertyName) { + Object value = translator.get(propertyName); + if (value != null) { + return (Duration) value; + } Long millis = getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); if (millis == null) { return null; @@ -114,8 +137,13 @@ public Duration getDuration(String propertyName) { return Duration.ofMillis(millis); } + @SuppressWarnings("unchecked") @Override public List getList(String propertyName) { + Object value = translator.get(propertyName); + if (value != null) { + return (List) value; + } List propertyValue = getPropertyValue( propertyName, @@ -123,8 +151,13 @@ public List getList(String propertyName) { return propertyValue == null ? Collections.emptyList() : propertyValue; } + @SuppressWarnings("unchecked") @Override public Map getMap(String propertyName) { + Object fixed = translator.get(propertyName); + if (fixed != null) { + return (Map) fixed; + } DeclarativeConfigProperties propertyValue = getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); if (propertyValue == null) { @@ -151,7 +184,7 @@ private T getPropertyValue( return null; } - String[] segments = getSegments(translate(property)); + String[] segments = getSegments(translator.translateProperty(property)); if (segments.length == 0) { return null; } @@ -168,21 +201,12 @@ private T getPropertyValue( return extractor.apply(target, lastPart); } - private String translate(String property) { - for (Map.Entry entry : translationMap.entrySet()) { - if (property.startsWith(entry.getKey())) { - return entry.getValue() + property.substring(entry.getKey().length()); - } - } - return property; - } - private static String[] getSegments(String property) { if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); } // Split the remainder of the property on "." - return property.split("\\."); + return property.replace('-', '_').split("\\."); } static String yamlPath(String property) { diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslator.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslator.java new file mode 100644 index 000000000..8edfd8673 --- /dev/null +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslator.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sdk.autoconfigure; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Nullable; + +@SuppressWarnings("NonApiType") +class PropertyTranslator { + // lookup order matters - we choose the first match + private final LinkedHashMap translationMap; + private final Map fixedValues; + + PropertyTranslator( + LinkedHashMap translationMap, Map fixedValues) { + this.translationMap = translationMap; + this.fixedValues = fixedValues; + } + + String translateProperty(String property) { + for (Map.Entry entry : translationMap.entrySet()) { + if (property.startsWith(entry.getKey())) { + return entry.getValue() + property.substring(entry.getKey().length()); + } + } + return property; + } + + @Nullable + public Object get(String propertyName) { + return fixedValues.get(propertyName); + } +} diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslatorBuilder.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslatorBuilder.java new file mode 100644 index 000000000..1b06c40a4 --- /dev/null +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslatorBuilder.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sdk.autoconfigure; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import java.util.LinkedHashMap; +import java.util.Map; + +public class PropertyTranslatorBuilder { + private final LinkedHashMap translationMap = new LinkedHashMap<>(); + private final Map fixedValues = new LinkedHashMap<>(); + + PropertyTranslatorBuilder() {} + + @CanIgnoreReturnValue + public PropertyTranslatorBuilder addTranslation(String propertyName, String yamlPath) { + translationMap.put(propertyName, yamlPath); + return this; + } + + @CanIgnoreReturnValue + public PropertyTranslatorBuilder addFixedValue(String propertyName, Object value) { + fixedValues.put(propertyName, value); + return this; + } + + PropertyTranslator build() { + return new PropertyTranslator(translationMap, fixedValues); + } +} diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java index e02940d1c..c8b223423 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java @@ -3,10 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sdk.autoconfigure; /* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ +package io.opentelemetry.contrib.sdk.autoconfigure; import static org.assertj.core.api.Assertions.assertThat; @@ -15,11 +12,8 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -28,56 +22,31 @@ class DeclarativeConfigPropertiesBridgeTest { - private static final String YAML = - "file_format: 0.4\n" - + "instrumentation/development:\n" - + " java:\n" - + " common:\n" - + " default-enabled: true\n" - + " runtime-telemetry:\n" - + " enabled: false\n" - + " example-instrumentation:\n" - + " string_key: value\n" - + " bool_key: true\n" - + " int_key: 1\n" - + " double_key: 1.1\n" - + " list_key:\n" - + " - value1\n" - + " - value2\n" - + " - true\n" - + " map_key:\n" - + " string_key1: value1\n" - + " string_key2: value2\n" - + " bool_key: true\n" - + " acme:\n" - + " full_name:\n" - + " preserved: true"; - private ConfigProperties bridge; private ConfigProperties emptyBridge; @BeforeEach void setup() { - bridge = createBridge(Collections.emptyMap()); + bridge = create(ConfigPropertiesUtil.propertyTranslatorBuilder()); OpenTelemetryConfigurationModel emptyModel = new OpenTelemetryConfigurationModel() .withAdditionalProperty("instrumentation/development", new InstrumentationModel()); SdkConfigProvider emptyConfigProvider = SdkConfigProvider.create(emptyModel); emptyBridge = - DeclarativeConfigPropertiesBridge.fromInstrumentationConfig( - Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig()), - Collections.emptyMap()); + ConfigPropertiesUtil.resolveInstrumentationConfig( + Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig())); } - private static DeclarativeConfigPropertiesBridge createBridge( - Map translationMap) { + private static ConfigProperties create(PropertyTranslatorBuilder builder) { OpenTelemetryConfigurationModel model = DeclarativeConfiguration.parse( - new ByteArrayInputStream(YAML.getBytes(StandardCharsets.UTF_8))); - return DeclarativeConfigPropertiesBridge.fromInstrumentationConfig( - Objects.requireNonNull(SdkConfigProvider.create(model).getInstrumentationConfig()), - translationMap); + DeclarativeConfigPropertiesBridgeTest.class + .getClassLoader() + .getResourceAsStream("config.yaml")); + SdkConfigProvider configProvider = SdkConfigProvider.create(model); + return ConfigPropertiesUtil.resolveInstrumentationConfig( + configProvider.getInstrumentationConfig(), builder); } @Test @@ -91,7 +60,6 @@ void getProperties() { .isTrue(); // common cases - assertThat(bridge.getBoolean("otel.instrumentation.common.default-enabled")).isTrue(); assertThat(bridge.getBoolean("otel.instrumentation.runtime-telemetry.enabled")).isFalse(); // check all the types @@ -154,9 +122,37 @@ void vendor() { } @Test - void translation() { - DeclarativeConfigPropertiesBridge propertiesBridge = - createBridge(Collections.singletonMap("acme", "acme.full_name")); + void vendorTranslation() { + ConfigProperties propertiesBridge = + create( + ConfigPropertiesUtil.propertyTranslatorBuilder() + .addTranslation("acme", "acme.full_name")); assertThat(propertiesBridge.getBoolean("acme.preserved")).isTrue(); } + + @Test + void agentCommonTranslation() { + assertThat( + create( + ConfigPropertiesUtil.propertyTranslatorBuilder() + .addTranslation( + "otel.instrumentation.common.default-enabled", + "common.default.enabled")) + .getBoolean("otel.instrumentation.common.default-enabled")) + .isFalse(); + } + + @Test + void agentTranslation() { + ConfigProperties bridge = + create( + ConfigPropertiesUtil.propertyTranslatorBuilder() + .addTranslation("otel.javaagent", "agent") + .addFixedValue("otel.javaagent.debug", true) + .addFixedValue("otel.javaagent.logging", "application")); + + assertThat(bridge.getBoolean("otel.javaagent.debug")).isTrue(); + assertThat(bridge.getBoolean("otel.javaagent.experimental.indy")).isTrue(); + assertThat(bridge.getString("otel.javaagent.logging")).isEqualTo("application"); + } } diff --git a/declarative-config-bridge/src/test/resources/config.yaml b/declarative-config-bridge/src/test/resources/config.yaml new file mode 100644 index 000000000..ef0ce9a8c --- /dev/null +++ b/declarative-config-bridge/src/test/resources/config.yaml @@ -0,0 +1,27 @@ +file_format: 0.4 +instrumentation/development: + java: + acme: + full_name: + preserved: true + agent: + experimental: + indy: true + common: + default: + enabled: false + runtime_telemetry: + enabled: false + example_instrumentation: + string_key: value + bool_key: true + int_key: 1 + double_key: 1.1 + list_key: + - value1 + - value2 + - true + map_key: + string_key1: value1 + string_key2: value2 + bool_key: true diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java index 297a47596..42b0f68be 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -15,6 +15,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel; @@ -51,7 +52,7 @@ public void customize(DeclarativeConfigurationCustomizer customizer) { customize( model, GcpAuthAutoConfigurationCustomizerProvider.getCredentials(), - ConfigPropertiesUtil.resolveModel(model)); + getConfigProperties(model)); return model; }); @@ -68,6 +69,11 @@ static void customize( customizeTracer(model, headerMap, configProperties); } + static ConfigProperties getConfigProperties(OpenTelemetryConfigurationModel model) { + return ConfigPropertiesUtil.resolveInstrumentationConfig( + SdkConfigProvider.create(model).getInstrumentationConfig()); + } + private static void customizeMeter( OpenTelemetryConfigurationModel model, Map headerMap, diff --git a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java index fd469eae0..8252f50c6 100644 --- a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java +++ b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java @@ -11,7 +11,6 @@ import static org.mockito.Mockito.when; import com.google.auth.oauth2.GoogleCredentials; -import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; @@ -52,7 +51,7 @@ void declarativeConfig() throws IOException { OpenTelemetryConfigurationModel model = DeclarativeConfiguration.parse( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); - ConfigProperties properties = ConfigPropertiesUtil.resolveModel(model); + ConfigProperties properties = GcpAuthCustomizerProvider.getConfigProperties(model); assertThat(GcpAuthAutoConfigurationCustomizerProvider.targetSignals(properties)) .containsExactly("metrics", "traces"); diff --git a/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java index 5606a53a3..b6f07a4fe 100644 --- a/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java +++ b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java @@ -10,7 +10,6 @@ import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; import io.opentelemetry.sdk.trace.SpanProcessor; -import java.util.Collections; @SuppressWarnings("rawtypes") @AutoService(ComponentProvider.class) @@ -24,7 +23,9 @@ public String getName() { public SpanProcessor create(DeclarativeConfigProperties config) { return StackTraceAutoConfig.create( ConfigPropertiesUtil.resolveConfig( - config, Collections.singletonMap(StackTraceAutoConfig.PREFIX, ""))); + config, + ConfigPropertiesUtil.propertyTranslatorBuilder() + .addTranslation(StackTraceAutoConfig.PREFIX, ""))); } @Override From 7bf95dfd1b0f25a9770e5233d7b22ac5bd13d87d Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 22 Jul 2025 18:36:13 +0200 Subject: [PATCH 29/41] add experimental- suffix, add test --- .../StackTraceComponentProvider.java | 2 +- .../StackTraceComponentProviderTest.java | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 span-stacktrace/src/test/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProviderTest.java diff --git a/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java index b6f07a4fe..5c37441f5 100644 --- a/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java +++ b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java @@ -16,7 +16,7 @@ public class StackTraceComponentProvider implements ComponentProvider { @Override public String getName() { - return "stacktrace"; + return "experimental-stacktrace"; } @Override diff --git a/span-stacktrace/src/test/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProviderTest.java b/span-stacktrace/src/test/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProviderTest.java new file mode 100644 index 000000000..edc2a8d8c --- /dev/null +++ b/span-stacktrace/src/test/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProviderTest.java @@ -0,0 +1,27 @@ +package io.opentelemetry.contrib.stacktrace; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class StackTraceComponentProviderTest { + @Test + void endToEnd() { + String yaml = + "file_format: 0.4\n" + + "tracer_provider:\n" + + " processors:\n" + + " - experimental-stacktrace:\n"; + + OpenTelemetrySdk openTelemetrySdk = + DeclarativeConfiguration.parseAndCreate( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + + assertThat(openTelemetrySdk.getSdkTracerProvider().toString()) + .contains("StackTraceSpanProcessor"); + } +} From 06cb01600a78863a98a1a08c538b598abd20c8a2 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 22 Jul 2025 18:37:25 +0200 Subject: [PATCH 30/41] add experimental- suffix, add test --- .../StackTraceComponentProviderTest.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/span-stacktrace/src/test/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProviderTest.java b/span-stacktrace/src/test/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProviderTest.java index edc2a8d8c..a2b4c4212 100644 --- a/span-stacktrace/src/test/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProviderTest.java +++ b/span-stacktrace/src/test/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProviderTest.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.contrib.stacktrace; import static org.assertj.core.api.Assertions.assertThat; @@ -10,18 +15,18 @@ class StackTraceComponentProviderTest { @Test - void endToEnd() { - String yaml = - "file_format: 0.4\n" - + "tracer_provider:\n" - + " processors:\n" - + " - experimental-stacktrace:\n"; + void endToEnd() { + String yaml = + "file_format: 0.4\n" + + "tracer_provider:\n" + + " processors:\n" + + " - experimental-stacktrace:\n"; - OpenTelemetrySdk openTelemetrySdk = - DeclarativeConfiguration.parseAndCreate( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + OpenTelemetrySdk openTelemetrySdk = + DeclarativeConfiguration.parseAndCreate( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); assertThat(openTelemetrySdk.getSdkTracerProvider().toString()) .contains("StackTraceSpanProcessor"); - } + } } From fedec511f368b1e81b259b64df8598d1abc095ce Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 24 Jul 2025 20:42:51 +0200 Subject: [PATCH 31/41] update bridge to match agent --- ...r.java => ConfigPropertiesTranslator.java} | 4 +- .../autoconfigure/ConfigPropertiesUtil.java | 51 +---------- .../DeclarativeConfigPropertiesBridge.java | 23 ++--- ...larativeConfigPropertiesBridgeBuilder.java | 76 ++++++++++++++++ .../PropertyTranslatorBuilder.java | 33 ------- .../ConfigPropertiesUtilTest.java | 75 ---------------- ...tiveConfigPropertiesBridgeBuilderTest.java | 89 +++++++++++++++++++ ...DeclarativeConfigPropertiesBridgeTest.java | 20 ++--- .../gcp/auth/GcpAuthCustomizerProvider.java | 5 +- .../StackTraceComponentProvider.java | 9 +- 10 files changed, 194 insertions(+), 191 deletions(-) rename declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/{PropertyTranslator.java => ConfigPropertiesTranslator.java} (93%) create mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilder.java delete mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslatorBuilder.java create mode 100644 declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslator.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java similarity index 93% rename from declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslator.java rename to declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java index 8edfd8673..5c54b04c7 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslator.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java @@ -10,12 +10,12 @@ import javax.annotation.Nullable; @SuppressWarnings("NonApiType") -class PropertyTranslator { +class ConfigPropertiesTranslator { // lookup order matters - we choose the first match private final LinkedHashMap translationMap; private final Map fixedValues; - PropertyTranslator( + ConfigPropertiesTranslator( LinkedHashMap translationMap, Map fixedValues) { this.translationMap = translationMap; this.fixedValues = fixedValues; diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index eaf18d584..1deb62b30 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -5,57 +5,14 @@ package io.opentelemetry.contrib.sdk.autoconfigure; -import io.opentelemetry.api.incubator.config.ConfigProvider; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import javax.annotation.Nullable; - +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ public final class ConfigPropertiesUtil { private ConfigPropertiesUtil() {} - /** Resolve {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ - public static ConfigProperties resolveConfigProperties( - AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { - ConfigProperties sdkConfigProperties = - AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); - if (sdkConfigProperties != null) { - return sdkConfigProperties; - } - ConfigProvider configProvider = - AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); - if (configProvider != null) { - return resolveInstrumentationConfig( - configProvider.getInstrumentationConfig(), propertyTranslatorBuilder()); - } - // Should never happen - throw new IllegalStateException( - "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); - } - - public static ConfigProperties resolveInstrumentationConfig( - @Nullable DeclarativeConfigProperties instrumentationConfig) { - return resolveInstrumentationConfig(instrumentationConfig, propertyTranslatorBuilder()); - } - - public static ConfigProperties resolveInstrumentationConfig( - @Nullable DeclarativeConfigProperties instrumentationConfig, - PropertyTranslatorBuilder builder) { - return DeclarativeConfigPropertiesBridge.fromInstrumentationConfig( - instrumentationConfig, builder.build()); - } - - public static ConfigProperties resolveConfig( - @Nullable DeclarativeConfigProperties config, PropertyTranslatorBuilder builder) { - return DeclarativeConfigPropertiesBridge.create(config, builder.build()); - } - public static String propertyYamlPath(String propertyName) { return DeclarativeConfigPropertiesBridge.yamlPath(propertyName); } - - public static PropertyTranslatorBuilder propertyTranslatorBuilder() { - return new PropertyTranslatorBuilder(); - } } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index 188c4e899..2b8983bd2 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -45,30 +45,19 @@ * common: * string_key: value * + * + *

    This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. */ final class DeclarativeConfigPropertiesBridge implements ConfigProperties { private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; - private final PropertyTranslator translator; + private final ConfigPropertiesTranslator translator; @Nullable private final DeclarativeConfigProperties baseNode; - static DeclarativeConfigPropertiesBridge fromInstrumentationConfig( - @Nullable DeclarativeConfigProperties instrumentationConfig, PropertyTranslator translator) { - if (instrumentationConfig == null) { - instrumentationConfig = DeclarativeConfigProperties.empty(); - } - return new DeclarativeConfigPropertiesBridge( - instrumentationConfig.getStructured("java", empty()), translator); - } - - static DeclarativeConfigPropertiesBridge create( - @Nullable DeclarativeConfigProperties node, PropertyTranslator translator) { - return new DeclarativeConfigPropertiesBridge(node, translator); - } - - private DeclarativeConfigPropertiesBridge( - @Nullable DeclarativeConfigProperties baseNode, PropertyTranslator translator) { + DeclarativeConfigPropertiesBridge( + @Nullable DeclarativeConfigProperties baseNode, ConfigPropertiesTranslator translator) { this.baseNode = baseNode; this.translator = translator; } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilder.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilder.java new file mode 100644 index 000000000..12caeb143 --- /dev/null +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilder.java @@ -0,0 +1,76 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sdk.autoconfigure; + +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * A builder for {@link DeclarativeConfigPropertiesBridge} that allows adding translations and fixed + * values for properties. + * + *

    This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class DeclarativeConfigPropertiesBridgeBuilder { + private final LinkedHashMap translationMap = new LinkedHashMap<>(); + private final Map fixedValues = new LinkedHashMap<>(); + + public DeclarativeConfigPropertiesBridgeBuilder() {} + + @CanIgnoreReturnValue + public DeclarativeConfigPropertiesBridgeBuilder addTranslation( + String propertyName, String yamlPath) { + translationMap.put(propertyName, yamlPath); + return this; + } + + @CanIgnoreReturnValue + public DeclarativeConfigPropertiesBridgeBuilder addFixedValue(String propertyName, Object value) { + fixedValues.put(propertyName, value); + return this; + } + + /** Resolve {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ + public ConfigProperties resolveConfigProperties( + AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { + ConfigProperties sdkConfigProperties = + AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); + if (sdkConfigProperties != null) { + return sdkConfigProperties; + } + ConfigProvider configProvider = + AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); + if (configProvider != null) { + return resolveInstrumentationConfig(configProvider.getInstrumentationConfig()); + } + // Should never happen + throw new IllegalStateException( + "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); + } + + public ConfigProperties resolveInstrumentationConfig( + @Nullable DeclarativeConfigProperties instrumentationConfig) { + if (instrumentationConfig == null) { + instrumentationConfig = DeclarativeConfigProperties.empty(); + } + return resolveConfig(instrumentationConfig.getStructured("java", empty())); + } + + public ConfigProperties resolveConfig(@Nullable DeclarativeConfigProperties config) { + return new DeclarativeConfigPropertiesBridge( + config, new ConfigPropertiesTranslator(translationMap, fixedValues)); + } +} diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslatorBuilder.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslatorBuilder.java deleted file mode 100644 index 1b06c40a4..000000000 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/PropertyTranslatorBuilder.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.sdk.autoconfigure; - -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import java.util.LinkedHashMap; -import java.util.Map; - -public class PropertyTranslatorBuilder { - private final LinkedHashMap translationMap = new LinkedHashMap<>(); - private final Map fixedValues = new LinkedHashMap<>(); - - PropertyTranslatorBuilder() {} - - @CanIgnoreReturnValue - public PropertyTranslatorBuilder addTranslation(String propertyName, String yamlPath) { - translationMap.put(propertyName, yamlPath); - return this; - } - - @CanIgnoreReturnValue - public PropertyTranslatorBuilder addFixedValue(String propertyName, Object value) { - fixedValues.put(propertyName, value); - return this; - } - - PropertyTranslator build() { - return new PropertyTranslator(translationMap, fixedValues); - } -} diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java index 9981ffdb2..f28f943d4 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.java @@ -6,85 +6,10 @@ package io.opentelemetry.contrib.sdk.autoconfigure; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import io.opentelemetry.api.incubator.config.ConfigProvider; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -@SuppressWarnings("DoNotMockAutoValue") class ConfigPropertiesUtilTest { - @Test - void shouldUseConfigPropertiesForAutoConfiguration() { - ConfigProperties configPropertiesMock = mock(ConfigProperties.class); - AutoConfiguredOpenTelemetrySdk sdkMock = mock(AutoConfiguredOpenTelemetrySdk.class); - try (MockedStatic autoConfigureUtilMock = - Mockito.mockStatic(AutoConfigureUtil.class)) { - autoConfigureUtilMock - .when(() -> AutoConfigureUtil.getConfig(sdkMock)) - .thenReturn(configPropertiesMock); - - ConfigProperties configProperties = ConfigPropertiesUtil.resolveConfigProperties(sdkMock); - - assertThat(configProperties).isSameAs(configPropertiesMock); - } - } - - @Test - void shouldUseConfigProviderForDeclarativeConfiguration() { - String propertyName = "testProperty"; - String expectedValue = "the value"; - DeclarativeConfigProperties javaNodeMock = mock(DeclarativeConfigProperties.class); - when(javaNodeMock.getString(propertyName)).thenReturn(expectedValue); - - DeclarativeConfigProperties instrumentationConfigMock = mock(DeclarativeConfigProperties.class); - when(instrumentationConfigMock.getStructured(eq("java"), any())).thenReturn(javaNodeMock); - - ConfigProvider configProviderMock = mock(ConfigProvider.class); - when(configProviderMock.getInstrumentationConfig()).thenReturn(instrumentationConfigMock); - - AutoConfiguredOpenTelemetrySdk sdkMock = mock(AutoConfiguredOpenTelemetrySdk.class); - - try (MockedStatic autoConfigureUtilMock = - Mockito.mockStatic(AutoConfigureUtil.class)) { - autoConfigureUtilMock.when(() -> AutoConfigureUtil.getConfig(sdkMock)).thenReturn(null); - autoConfigureUtilMock - .when(() -> AutoConfigureUtil.getConfigProvider(sdkMock)) - .thenReturn(configProviderMock); - - ConfigProperties configProperties = ConfigPropertiesUtil.resolveConfigProperties(sdkMock); - - assertThat(configProperties.getString(propertyName)).isEqualTo(expectedValue); - } - } - - @Test - void shouldUseConfigProviderForDeclarativeConfiguration_noInstrumentationConfig() { - AutoConfiguredOpenTelemetrySdk sdkMock = mock(AutoConfiguredOpenTelemetrySdk.class); - ConfigProvider configProviderMock = mock(ConfigProvider.class); - when(configProviderMock.getInstrumentationConfig()).thenReturn(null); - - try (MockedStatic autoConfigureUtilMock = - Mockito.mockStatic(AutoConfigureUtil.class)) { - autoConfigureUtilMock.when(() -> AutoConfigureUtil.getConfig(sdkMock)).thenReturn(null); - autoConfigureUtilMock - .when(() -> AutoConfigureUtil.getConfigProvider(sdkMock)) - .thenReturn(configProviderMock); - - ConfigProperties configProperties = ConfigPropertiesUtil.resolveConfigProperties(sdkMock); - - assertThat(configProperties.getString("testProperty")).isEqualTo(null); - } - } - @Test void propertyYamlPath() { assertThat(ConfigPropertiesUtil.propertyYamlPath("google.otel.auth.target.signals")) diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java new file mode 100644 index 000000000..504edb196 --- /dev/null +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java @@ -0,0 +1,89 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sdk.autoconfigure; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +class DeclarativeConfigPropertiesBridgeBuilderTest { + @Test + void shouldUseConfigPropertiesForAutoConfiguration() { + ConfigProperties configPropertiesMock = mock(ConfigProperties.class); + AutoConfiguredOpenTelemetrySdk sdkMock = mock(AutoConfiguredOpenTelemetrySdk.class); + try (MockedStatic autoConfigureUtilMock = + Mockito.mockStatic(AutoConfigureUtil.class)) { + autoConfigureUtilMock + .when(() -> AutoConfigureUtil.getConfig(sdkMock)) + .thenReturn(configPropertiesMock); + + ConfigProperties configProperties = + new DeclarativeConfigPropertiesBridgeBuilder().resolveConfigProperties(sdkMock); + + assertThat(configProperties).isSameAs(configPropertiesMock); + } + } + + @Test + void shouldUseConfigProviderForDeclarativeConfiguration() { + String propertyName = "testProperty"; + String expectedValue = "the value"; + DeclarativeConfigProperties javaNodeMock = mock(DeclarativeConfigProperties.class); + when(javaNodeMock.getString(propertyName)).thenReturn(expectedValue); + + DeclarativeConfigProperties instrumentationConfigMock = mock(DeclarativeConfigProperties.class); + when(instrumentationConfigMock.getStructured(eq("java"), any())).thenReturn(javaNodeMock); + + ConfigProvider configProviderMock = mock(ConfigProvider.class); + when(configProviderMock.getInstrumentationConfig()).thenReturn(instrumentationConfigMock); + + AutoConfiguredOpenTelemetrySdk sdkMock = mock(AutoConfiguredOpenTelemetrySdk.class); + + try (MockedStatic autoConfigureUtilMock = + Mockito.mockStatic(AutoConfigureUtil.class)) { + autoConfigureUtilMock.when(() -> AutoConfigureUtil.getConfig(sdkMock)).thenReturn(null); + autoConfigureUtilMock + .when(() -> AutoConfigureUtil.getConfigProvider(sdkMock)) + .thenReturn(configProviderMock); + + ConfigProperties configProperties = + new DeclarativeConfigPropertiesBridgeBuilder().resolveConfigProperties(sdkMock); + + assertThat(configProperties.getString(propertyName)).isEqualTo(expectedValue); + } + } + + @Test + void shouldUseConfigProviderForDeclarativeConfiguration_noInstrumentationConfig() { + AutoConfiguredOpenTelemetrySdk sdkMock = mock(AutoConfiguredOpenTelemetrySdk.class); + ConfigProvider configProviderMock = mock(ConfigProvider.class); + when(configProviderMock.getInstrumentationConfig()).thenReturn(null); + + try (MockedStatic autoConfigureUtilMock = + Mockito.mockStatic(AutoConfigureUtil.class)) { + autoConfigureUtilMock.when(() -> AutoConfigureUtil.getConfig(sdkMock)).thenReturn(null); + autoConfigureUtilMock + .when(() -> AutoConfigureUtil.getConfigProvider(sdkMock)) + .thenReturn(configProviderMock); + + ConfigProperties configProperties = + new DeclarativeConfigPropertiesBridgeBuilder().resolveConfigProperties(sdkMock); + + assertThat(configProperties.getString("testProperty")).isEqualTo(null); + } + } +} diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java index c8b223423..746eed875 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java @@ -27,26 +27,26 @@ class DeclarativeConfigPropertiesBridgeTest { @BeforeEach void setup() { - bridge = create(ConfigPropertiesUtil.propertyTranslatorBuilder()); + bridge = create(new DeclarativeConfigPropertiesBridgeBuilder()); OpenTelemetryConfigurationModel emptyModel = new OpenTelemetryConfigurationModel() .withAdditionalProperty("instrumentation/development", new InstrumentationModel()); SdkConfigProvider emptyConfigProvider = SdkConfigProvider.create(emptyModel); emptyBridge = - ConfigPropertiesUtil.resolveInstrumentationConfig( - Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig())); + new DeclarativeConfigPropertiesBridgeBuilder() + .resolveInstrumentationConfig( + Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig())); } - private static ConfigProperties create(PropertyTranslatorBuilder builder) { + private static ConfigProperties create(DeclarativeConfigPropertiesBridgeBuilder builder) { OpenTelemetryConfigurationModel model = DeclarativeConfiguration.parse( DeclarativeConfigPropertiesBridgeTest.class .getClassLoader() .getResourceAsStream("config.yaml")); - SdkConfigProvider configProvider = SdkConfigProvider.create(model); - return ConfigPropertiesUtil.resolveInstrumentationConfig( - configProvider.getInstrumentationConfig(), builder); + return builder.resolveInstrumentationConfig( + SdkConfigProvider.create(model).getInstrumentationConfig()); } @Test @@ -125,7 +125,7 @@ void vendor() { void vendorTranslation() { ConfigProperties propertiesBridge = create( - ConfigPropertiesUtil.propertyTranslatorBuilder() + new DeclarativeConfigPropertiesBridgeBuilder() .addTranslation("acme", "acme.full_name")); assertThat(propertiesBridge.getBoolean("acme.preserved")).isTrue(); } @@ -134,7 +134,7 @@ void vendorTranslation() { void agentCommonTranslation() { assertThat( create( - ConfigPropertiesUtil.propertyTranslatorBuilder() + new DeclarativeConfigPropertiesBridgeBuilder() .addTranslation( "otel.instrumentation.common.default-enabled", "common.default.enabled")) @@ -146,7 +146,7 @@ void agentCommonTranslation() { void agentTranslation() { ConfigProperties bridge = create( - ConfigPropertiesUtil.propertyTranslatorBuilder() + new DeclarativeConfigPropertiesBridgeBuilder() .addTranslation("otel.javaagent", "agent") .addFixedValue("otel.javaagent.debug", true) .addFixedValue("otel.javaagent.logging", "application")); diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java index 42b0f68be..51385b534 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -12,6 +12,7 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.auto.service.AutoService; import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; +import io.opentelemetry.contrib.sdk.autoconfigure.DeclarativeConfigPropertiesBridgeBuilder; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; @@ -70,8 +71,8 @@ static void customize( } static ConfigProperties getConfigProperties(OpenTelemetryConfigurationModel model) { - return ConfigPropertiesUtil.resolveInstrumentationConfig( - SdkConfigProvider.create(model).getInstrumentationConfig()); + return new DeclarativeConfigPropertiesBridgeBuilder() + .resolveInstrumentationConfig(SdkConfigProvider.create(model).getInstrumentationConfig()); } private static void customizeMeter( diff --git a/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java index 5c37441f5..cfa36ae6d 100644 --- a/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java +++ b/span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceComponentProvider.java @@ -7,7 +7,7 @@ import com.google.auto.service.AutoService; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; +import io.opentelemetry.contrib.sdk.autoconfigure.DeclarativeConfigPropertiesBridgeBuilder; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; import io.opentelemetry.sdk.trace.SpanProcessor; @@ -22,10 +22,9 @@ public String getName() { @Override public SpanProcessor create(DeclarativeConfigProperties config) { return StackTraceAutoConfig.create( - ConfigPropertiesUtil.resolveConfig( - config, - ConfigPropertiesUtil.propertyTranslatorBuilder() - .addTranslation(StackTraceAutoConfig.PREFIX, ""))); + new DeclarativeConfigPropertiesBridgeBuilder() + .addTranslation(StackTraceAutoConfig.PREFIX, "") + .resolveConfig(config)); } @Override From 93b93e1ac75cb013828e842ea31b1d4720aff46c Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 24 Jul 2025 20:49:14 +0200 Subject: [PATCH 32/41] update bridge to match agent --- .../sdk/autoconfigure/ConfigPropertiesTranslator.java | 5 +++-- .../DeclarativeConfigPropertiesBridge.java | 10 ++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java index 5c54b04c7..9ce1ebf20 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java @@ -30,8 +30,9 @@ String translateProperty(String property) { return property; } + @SuppressWarnings("unchecked") @Nullable - public Object get(String propertyName) { - return fixedValues.get(propertyName); + public T get(String propertyName) { + return (T) fixedValues.get(propertyName); } } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index 2b8983bd2..f38411490 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -126,12 +126,11 @@ public Duration getDuration(String propertyName) { return Duration.ofMillis(millis); } - @SuppressWarnings("unchecked") @Override public List getList(String propertyName) { - Object value = translator.get(propertyName); + List value = translator.get(propertyName); if (value != null) { - return (List) value; + return value; } List propertyValue = getPropertyValue( @@ -140,12 +139,11 @@ public List getList(String propertyName) { return propertyValue == null ? Collections.emptyList() : propertyValue; } - @SuppressWarnings("unchecked") @Override public Map getMap(String propertyName) { - Object fixed = translator.get(propertyName); + Map fixed = translator.get(propertyName); if (fixed != null) { - return (Map) fixed; + return fixed; } DeclarativeConfigProperties propertyValue = getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); From cdbe87b713e593b7dee4aa9decaa1c77d0a008d1 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 24 Jul 2025 20:55:27 +0200 Subject: [PATCH 33/41] Revert "update bridge to match agent" This reverts commit 2e2bb79add74c6790e87d4fc0b24b80edff848e5. --- .../sdk/autoconfigure/ConfigPropertiesTranslator.java | 5 ++--- .../DeclarativeConfigPropertiesBridge.java | 10 ++++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java index 9ce1ebf20..5c54b04c7 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java @@ -30,9 +30,8 @@ String translateProperty(String property) { return property; } - @SuppressWarnings("unchecked") @Nullable - public T get(String propertyName) { - return (T) fixedValues.get(propertyName); + public Object get(String propertyName) { + return fixedValues.get(propertyName); } } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index f38411490..2b8983bd2 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -126,11 +126,12 @@ public Duration getDuration(String propertyName) { return Duration.ofMillis(millis); } + @SuppressWarnings("unchecked") @Override public List getList(String propertyName) { - List value = translator.get(propertyName); + Object value = translator.get(propertyName); if (value != null) { - return value; + return (List) value; } List propertyValue = getPropertyValue( @@ -139,11 +140,12 @@ public List getList(String propertyName) { return propertyValue == null ? Collections.emptyList() : propertyValue; } + @SuppressWarnings("unchecked") @Override public Map getMap(String propertyName) { - Map fixed = translator.get(propertyName); + Object fixed = translator.get(propertyName); if (fixed != null) { - return fixed; + return (Map) fixed; } DeclarativeConfigProperties propertyValue = getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); From e18a052f3001b11339a5294fad3ffde4137df59c Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 24 Jul 2025 21:21:56 +0200 Subject: [PATCH 34/41] update bridge to match agent --- .../DeclarativeConfigPropertiesBridgeBuilderTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java index 504edb196..1dc8ad9b3 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java @@ -20,6 +20,7 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; +@SuppressWarnings("DoNotMockAutoValue") class DeclarativeConfigPropertiesBridgeBuilderTest { @Test void shouldUseConfigPropertiesForAutoConfiguration() { From 933fb80426f69999201881a1296265ce266754bf Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 4 Aug 2025 14:46:42 +0200 Subject: [PATCH 35/41] Update gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java Co-authored-by: Pranav Sharma --- .../gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java | 1 + 1 file changed, 1 insertion(+) 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 8b241755f..148448afe 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 @@ -161,6 +161,7 @@ private static boolean isSignalTargeted(String checkSignal, ConfigProperties con targetedSignal.equals(checkSignal) || targetedSignal.equals(SIGNAL_TYPE_ALL)); } + @VisibleForTesting static List targetSignals(ConfigProperties configProperties) { return Objects.requireNonNull( ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getConfiguredValue( From df08db5bc4ac7cab7cdc006797d155c35229c084 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 4 Aug 2025 14:46:56 +0200 Subject: [PATCH 36/41] Update gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java Co-authored-by: Pranav Sharma --- .../contrib/gcp/auth/GcpAuthCustomizerProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java index 51385b534..86518ae2d 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java @@ -59,6 +59,7 @@ public void customize(DeclarativeConfigurationCustomizer customizer) { }); } + @VisibleForTesting static void customize( OpenTelemetryConfigurationModel model, GoogleCredentials credentials, From bbc3bfb6f100a8711f0af9dc286ed5dcdb44f1aa Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 4 Aug 2025 14:48:29 +0200 Subject: [PATCH 37/41] pr review --- .../contrib/gcp/auth/ConfigurableOption.java | 8 +++----- ...cpAuthDeclarativeConfigurationCustomizerProvider.java} | 3 ++- ...thDeclarativeConfigurationCustomizerProviderTest.java} | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) rename gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/{GcpAuthCustomizerProvider.java => GcpAuthDeclarativeConfigurationCustomizerProvider.java} (98%) rename gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/{GcpAuthCustomizerProviderTest.java => GcpAuthDeclarativeConfigurationCustomizerProviderTest.java} (88%) 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 54649c7a6..572baa8b8 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 @@ -92,8 +92,7 @@ String getUserReadableName() { } /** - * Retrieves the configured value for this option. This method checks the environment variable - * first and then the system property. + * Retrieves the configured value for this option. * * @return The configured value as a string, or throws an exception if not configured. * @throws ConfigurationException if neither the environment variable nor the system property is @@ -113,10 +112,9 @@ T getRequiredConfiguredValue( } /** - * Retrieves the configured value for this option. This method checks the environment variable - * first and then the system property. + * Retrieves the configured value for this option. * - * @return The configured value as a string, or throws an exception if not configured. + * @return The configured value as a string, or {@code null} if not configured. */ @Nullable T getConfiguredValue( diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java similarity index 98% rename from gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java rename to gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java index 86518ae2d..64ead75cd 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java @@ -11,6 +11,7 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.auto.service.AutoService; +import com.google.common.annotations.VisibleForTesting; import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil; import io.opentelemetry.contrib.sdk.autoconfigure.DeclarativeConfigPropertiesBridgeBuilder; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -37,7 +38,7 @@ import javax.annotation.Nullable; @AutoService(DeclarativeConfigurationCustomizerProvider.class) -public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { +public class GcpAuthDeclarativeConfigurationCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { static final String SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION = String.format( diff --git a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProviderTest.java similarity index 88% rename from gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java rename to gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProviderTest.java index 8252f50c6..f4b3a7f28 100644 --- a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProviderTest.java +++ b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProviderTest.java @@ -5,7 +5,7 @@ package io.opentelemetry.contrib.gcp.auth; -import static io.opentelemetry.contrib.gcp.auth.GcpAuthCustomizerProvider.SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION; +import static io.opentelemetry.contrib.gcp.auth.GcpAuthDeclarativeConfigurationCustomizerProvider.SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -20,7 +20,7 @@ import java.util.Collections; import org.junit.jupiter.api.Test; -class GcpAuthCustomizerProviderTest { +class GcpAuthDeclarativeConfigurationCustomizerProviderTest { @Test void declarativeConfig() throws IOException { @@ -51,7 +51,7 @@ void declarativeConfig() throws IOException { OpenTelemetryConfigurationModel model = DeclarativeConfiguration.parse( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); - ConfigProperties properties = GcpAuthCustomizerProvider.getConfigProperties(model); + ConfigProperties properties = GcpAuthDeclarativeConfigurationCustomizerProvider.getConfigProperties(model); assertThat(GcpAuthAutoConfigurationCustomizerProvider.targetSignals(properties)) .containsExactly("metrics", "traces"); @@ -64,7 +64,7 @@ void declarativeConfig() throws IOException { .thenReturn( Collections.singletonMap("x-goog-user-project", Collections.singletonList("qp"))); - GcpAuthCustomizerProvider.customize(model, credentials, properties); + GcpAuthDeclarativeConfigurationCustomizerProvider.customize(model, credentials, properties); String header = "headers=\\[io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel@.*\\[name=x-goog-user-project,value=qp]"; From 187b278fafad8c1cba13b82d8ee9d0a07511e951 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 4 Aug 2025 15:01:29 +0200 Subject: [PATCH 38/41] pr review --- ...uthAutoConfigurationCustomizerProvider.java | 18 +++++++++++++++--- ...arativeConfigurationCustomizerProvider.java | 6 +++--- 2 files changed, 18 insertions(+), 6 deletions(-) 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 148448afe..5b3cc925d 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 @@ -7,6 +7,7 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.auto.service.AutoService; +import com.google.common.annotations.VisibleForTesting; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.contrib.gcp.auth.GoogleAuthException.Reason; @@ -124,7 +125,7 @@ public int order() { private static SpanExporter customizeSpanExporter( SpanExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { - if (shouldConfigureExporter( + if (shouldCustomizeExporter( SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, configProperties)) { return addAuthorizationHeaders(exporter, credentials, configProperties); } @@ -133,14 +134,25 @@ private static SpanExporter customizeSpanExporter( private static MetricExporter customizeMetricExporter( MetricExporter exporter, GoogleCredentials credentials, ConfigProperties configProperties) { - if (shouldConfigureExporter( + if (shouldCustomizeExporter( SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_FIX_SUGGESTION, configProperties)) { return addAuthorizationHeaders(exporter, credentials, configProperties); } return exporter; } - static boolean shouldConfigureExporter( + /** + * Utility method to check whether OTLP exporters should be customized for the given target + * signal. + * + * @param signal The target signal to check against. Could be one of {@value SIGNAL_TYPE_TRACES}, + * {@value SIGNAL_TYPE_METRICS} or {@value SIGNAL_TYPE_ALL}. + * @param fixSuggestion A warning to alert the user that auth extension is not configured for the + * provided target signal. + * @param configProperties The {@link ConfigProperties} object used to configure the extension. + * @return A boolean indicating whether the OTLP exporters should be customized or not. + */ + static boolean shouldCustomizeExporter( String signal, String fixSuggestion, ConfigProperties configProperties) { if (isSignalTargeted(signal, configProperties)) { return true; diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java index 64ead75cd..c312f47fc 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java @@ -7,7 +7,7 @@ import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_METRICS; import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_TRACES; -import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.shouldConfigureExporter; +import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.shouldCustomizeExporter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auto.service.AutoService; @@ -86,7 +86,7 @@ private static void customizeMeter( return; } - if (shouldConfigureExporter( + if (shouldCustomizeExporter( SIGNAL_TYPE_METRICS, SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION, configProperties)) { for (MetricReaderModel reader : meterProvider.getReaders()) { if (reader.getPeriodic() != null) { @@ -122,7 +122,7 @@ private static void customizeTracer( return; } - if (shouldConfigureExporter( + if (shouldCustomizeExporter( SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION, configProperties)) { for (SpanProcessorModel processor : tracerProvider.getProcessors()) { BatchSpanProcessorModel batch = processor.getBatch(); From c5c8e86f1497d4a7079c38fe28306086e6189dec Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 4 Aug 2025 15:32:16 +0200 Subject: [PATCH 39/41] pr review --- .../GcpAuthDeclarativeConfigurationCustomizerProvider.java | 3 ++- .../GcpAuthDeclarativeConfigurationCustomizerProviderTest.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java index c312f47fc..1cefdc64c 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java @@ -38,7 +38,8 @@ import javax.annotation.Nullable; @AutoService(DeclarativeConfigurationCustomizerProvider.class) -public class GcpAuthDeclarativeConfigurationCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { +public class GcpAuthDeclarativeConfigurationCustomizerProvider + implements DeclarativeConfigurationCustomizerProvider { static final String SIGNAL_TARGET_WARNING_YAML_FIX_SUGGESTION = String.format( diff --git a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProviderTest.java b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProviderTest.java index f4b3a7f28..ca234a0e3 100644 --- a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProviderTest.java +++ b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProviderTest.java @@ -51,7 +51,8 @@ void declarativeConfig() throws IOException { OpenTelemetryConfigurationModel model = DeclarativeConfiguration.parse( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); - ConfigProperties properties = GcpAuthDeclarativeConfigurationCustomizerProvider.getConfigProperties(model); + ConfigProperties properties = + GcpAuthDeclarativeConfigurationCustomizerProvider.getConfigProperties(model); assertThat(GcpAuthAutoConfigurationCustomizerProvider.targetSignals(properties)) .containsExactly("metrics", "traces"); From 682fc6563b48d94d09a24e06622c405c9066decb Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 15 Aug 2025 13:08:30 +0200 Subject: [PATCH 40/41] update config bridge from agent --- .../ConfigPropertiesTranslator.java | 37 -------- .../autoconfigure/ConfigPropertiesUtil.java | 15 ++- .../DeclarativeConfigPropertiesBridge.java | 95 ++++++++----------- ...larativeConfigPropertiesBridgeBuilder.java | 66 +++++++++---- ...tiveConfigPropertiesBridgeBuilderTest.java | 8 +- ...DeclarativeConfigPropertiesBridgeTest.java | 26 ++--- ...rativeConfigurationCustomizerProvider.java | 2 +- 7 files changed, 104 insertions(+), 145 deletions(-) delete mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java deleted file mode 100644 index 5c54b04c7..000000000 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesTranslator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.sdk.autoconfigure; - -import java.util.LinkedHashMap; -import java.util.Map; -import javax.annotation.Nullable; - -@SuppressWarnings("NonApiType") -class ConfigPropertiesTranslator { - // lookup order matters - we choose the first match - private final LinkedHashMap translationMap; - private final Map fixedValues; - - ConfigPropertiesTranslator( - LinkedHashMap translationMap, Map fixedValues) { - this.translationMap = translationMap; - this.fixedValues = fixedValues; - } - - String translateProperty(String property) { - for (Map.Entry entry : translationMap.entrySet()) { - if (property.startsWith(entry.getKey())) { - return entry.getValue() + property.substring(entry.getKey().length()); - } - } - return property; - } - - @Nullable - public Object get(String propertyName) { - return fixedValues.get(propertyName); - } -} diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index 1deb62b30..eff0b7706 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -5,14 +5,19 @@ package io.opentelemetry.contrib.sdk.autoconfigure; -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ public final class ConfigPropertiesUtil { private ConfigPropertiesUtil() {} public static String propertyYamlPath(String propertyName) { - return DeclarativeConfigPropertiesBridge.yamlPath(propertyName); + return yamlPath(propertyName); } + + static String yamlPath(String property) { + String[] segments = DeclarativeConfigPropertiesBridge.getSegments(property); + if (segments.length == 0) { + throw new IllegalArgumentException("Invalid property: " + property); + } + + return "'instrumentation/development' / 'java' / '" + String.join("' / '", segments) + "'"; + } } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java index 2b8983bd2..bc7f4b117 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.java @@ -14,6 +14,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.BiFunction; import javax.annotation.Nullable; @@ -45,81 +46,60 @@ * common: * string_key: value * - * - *

    This class is internal and is hence not for public use. Its APIs are unstable and can change - * at any time. */ final class DeclarativeConfigPropertiesBridge implements ConfigProperties { private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; - private final ConfigPropertiesTranslator translator; - @Nullable private final DeclarativeConfigProperties baseNode; + private final DeclarativeConfigProperties baseNode; + + // lookup order matters - we choose the first match + private final Map mappings; + private final Map overrideValues; DeclarativeConfigPropertiesBridge( - @Nullable DeclarativeConfigProperties baseNode, ConfigPropertiesTranslator translator) { - this.baseNode = baseNode; - this.translator = translator; + DeclarativeConfigProperties baseNode, + Map mappings, + Map overrideValues) { + this.baseNode = Objects.requireNonNull(baseNode); + this.mappings = mappings; + this.overrideValues = overrideValues; } @Nullable @Override public String getString(String propertyName) { - Object value = translator.get(propertyName); - if (value != null) { - return value.toString(); - } - return getPropertyValue(propertyName, DeclarativeConfigProperties::getString); + return getPropertyValue(propertyName, String.class, DeclarativeConfigProperties::getString); } @Nullable @Override public Boolean getBoolean(String propertyName) { - Object value = translator.get(propertyName); - if (value != null) { - return (Boolean) value; - } - return getPropertyValue(propertyName, DeclarativeConfigProperties::getBoolean); + return getPropertyValue(propertyName, Boolean.class, DeclarativeConfigProperties::getBoolean); } @Nullable @Override public Integer getInt(String propertyName) { - Object value = translator.get(propertyName); - if (value != null) { - return (Integer) value; - } - return getPropertyValue(propertyName, DeclarativeConfigProperties::getInt); + return getPropertyValue(propertyName, Integer.class, DeclarativeConfigProperties::getInt); } @Nullable @Override public Long getLong(String propertyName) { - Object value = translator.get(propertyName); - if (value != null) { - return (Long) value; - } - return getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + return getPropertyValue(propertyName, Long.class, DeclarativeConfigProperties::getLong); } @Nullable @Override public Double getDouble(String propertyName) { - Object value = translator.get(propertyName); - if (value != null) { - return (Double) value; - } - return getPropertyValue(propertyName, DeclarativeConfigProperties::getDouble); + return getPropertyValue(propertyName, Double.class, DeclarativeConfigProperties::getDouble); } @Nullable @Override public Duration getDuration(String propertyName) { - Object value = translator.get(propertyName); - if (value != null) { - return (Duration) value; - } - Long millis = getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + Long millis = getPropertyValue(propertyName, Long.class, DeclarativeConfigProperties::getLong); if (millis == null) { return null; } @@ -129,13 +109,10 @@ public Duration getDuration(String propertyName) { @SuppressWarnings("unchecked") @Override public List getList(String propertyName) { - Object value = translator.get(propertyName); - if (value != null) { - return (List) value; - } List propertyValue = getPropertyValue( propertyName, + List.class, (properties, lastPart) -> properties.getScalarList(lastPart, String.class)); return propertyValue == null ? Collections.emptyList() : propertyValue; } @@ -143,12 +120,11 @@ public List getList(String propertyName) { @SuppressWarnings("unchecked") @Override public Map getMap(String propertyName) { - Object fixed = translator.get(propertyName); - if (fixed != null) { - return (Map) fixed; - } DeclarativeConfigProperties propertyValue = - getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); + getPropertyValue( + propertyName, + DeclarativeConfigProperties.class, + DeclarativeConfigProperties::getStructured); if (propertyValue == null) { return Collections.emptyMap(); } @@ -168,12 +144,15 @@ public Map getMap(String propertyName) { @Nullable private T getPropertyValue( - String property, BiFunction extractor) { - if (baseNode == null) { - return null; + String property, + Class clazz, + BiFunction extractor) { + T override = clazz.cast(overrideValues.get(property)); + if (override != null) { + return override; } - String[] segments = getSegments(translator.translateProperty(property)); + String[] segments = getSegments(translateProperty(property)); if (segments.length == 0) { return null; } @@ -190,7 +169,7 @@ private T getPropertyValue( return extractor.apply(target, lastPart); } - private static String[] getSegments(String property) { + static String[] getSegments(String property) { if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); } @@ -198,12 +177,12 @@ private static String[] getSegments(String property) { return property.replace('-', '_').split("\\."); } - static String yamlPath(String property) { - String[] segments = getSegments(property); - if (segments.length == 0) { - throw new IllegalArgumentException("Invalid property: " + property); + private String translateProperty(String property) { + for (Map.Entry entry : mappings.entrySet()) { + if (property.startsWith(entry.getKey())) { + return entry.getValue() + property.substring(entry.getKey().length()); + } } - - return "'instrumentation/development' / 'java' / '" + String.join("' / '", segments) + "'"; + return property; } } diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilder.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilder.java index 12caeb143..7aafd4210 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilder.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilder.java @@ -13,6 +13,7 @@ import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nullable; @@ -20,32 +21,49 @@ /** * A builder for {@link DeclarativeConfigPropertiesBridge} that allows adding translations and fixed * values for properties. - * - *

    This class is internal and is hence not for public use. Its APIs are unstable and can change - * at any time. */ public class DeclarativeConfigPropertiesBridgeBuilder { - private final LinkedHashMap translationMap = new LinkedHashMap<>(); - private final Map fixedValues = new LinkedHashMap<>(); + /** + * order is important here, so we use LinkedHashMap - see {@link #addMapping(String, String)} for + * more details + */ + private final Map mappings = new LinkedHashMap<>(); + + private final Map overrideValues = new HashMap<>(); public DeclarativeConfigPropertiesBridgeBuilder() {} + /** + * Adds a mapping from a property prefix to a YAML path. + * + *

    For example, if the property prefix is "otel.javaagent" and the YAML path is "agent", then + * any property starting with "otel.javaagent." will be resolved against the "agent" node in the + * instrumentation/java section of the YAML configuration. + * + * @param propertyPrefix the prefix of the property to translate + * @param yamlPath the YAML path to resolve the property against + */ @CanIgnoreReturnValue - public DeclarativeConfigPropertiesBridgeBuilder addTranslation( - String propertyName, String yamlPath) { - translationMap.put(propertyName, yamlPath); + public DeclarativeConfigPropertiesBridgeBuilder addMapping( + String propertyPrefix, String yamlPath) { + mappings.put(propertyPrefix, yamlPath); return this; } + /** + * Adds a fixed override value for a property. + * + * @param propertyName the name of the property to override + * @param value the value to return when the property is requested + */ @CanIgnoreReturnValue - public DeclarativeConfigPropertiesBridgeBuilder addFixedValue(String propertyName, Object value) { - fixedValues.put(propertyName, value); + public DeclarativeConfigPropertiesBridgeBuilder addOverride(String propertyName, Object value) { + overrideValues.put(propertyName, value); return this; } - /** Resolve {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ - public ConfigProperties resolveConfigProperties( - AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { + /** Build {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ + public ConfigProperties build(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { ConfigProperties sdkConfigProperties = AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); if (sdkConfigProperties != null) { @@ -54,23 +72,31 @@ public ConfigProperties resolveConfigProperties( ConfigProvider configProvider = AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); if (configProvider != null) { - return resolveInstrumentationConfig(configProvider.getInstrumentationConfig()); + return buildFromInstrumentationConfig(configProvider.getInstrumentationConfig()); } // Should never happen throw new IllegalStateException( "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); } - public ConfigProperties resolveInstrumentationConfig( + /** + * Build {@link ConfigProperties} from the {@link DeclarativeConfigProperties} provided by the + * instrumentation configuration. + * + *

    If the provided {@code instrumentationConfig} is null, an empty {@link + * DeclarativeConfigProperties} will be used. + * + * @param instrumentationConfig the instrumentation configuration to build from + * @return a new instance of {@link ConfigProperties} + */ + public ConfigProperties buildFromInstrumentationConfig( @Nullable DeclarativeConfigProperties instrumentationConfig) { + // leave the name "build" for a future method that builds from a DeclarativeConfigProperties + // instance that doesn't come from the top-level instrumentation config if (instrumentationConfig == null) { instrumentationConfig = DeclarativeConfigProperties.empty(); } - return resolveConfig(instrumentationConfig.getStructured("java", empty())); - } - - public ConfigProperties resolveConfig(@Nullable DeclarativeConfigProperties config) { return new DeclarativeConfigPropertiesBridge( - config, new ConfigPropertiesTranslator(translationMap, fixedValues)); + instrumentationConfig.getStructured("java", empty()), mappings, overrideValues); } } diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java index 1dc8ad9b3..e07a7fbf7 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilderTest.java @@ -33,7 +33,7 @@ void shouldUseConfigPropertiesForAutoConfiguration() { .thenReturn(configPropertiesMock); ConfigProperties configProperties = - new DeclarativeConfigPropertiesBridgeBuilder().resolveConfigProperties(sdkMock); + new DeclarativeConfigPropertiesBridgeBuilder().build(sdkMock); assertThat(configProperties).isSameAs(configPropertiesMock); } @@ -62,7 +62,7 @@ void shouldUseConfigProviderForDeclarativeConfiguration() { .thenReturn(configProviderMock); ConfigProperties configProperties = - new DeclarativeConfigPropertiesBridgeBuilder().resolveConfigProperties(sdkMock); + new DeclarativeConfigPropertiesBridgeBuilder().build(sdkMock); assertThat(configProperties.getString(propertyName)).isEqualTo(expectedValue); } @@ -82,9 +82,9 @@ void shouldUseConfigProviderForDeclarativeConfiguration_noInstrumentationConfig( .thenReturn(configProviderMock); ConfigProperties configProperties = - new DeclarativeConfigPropertiesBridgeBuilder().resolveConfigProperties(sdkMock); + new DeclarativeConfigPropertiesBridgeBuilder().build(sdkMock); - assertThat(configProperties.getString("testProperty")).isEqualTo(null); + assertThat(configProperties.getString("testProperty")).isNull(); } } } diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java index 746eed875..405cecc1c 100644 --- a/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeTest.java @@ -35,7 +35,7 @@ void setup() { SdkConfigProvider emptyConfigProvider = SdkConfigProvider.create(emptyModel); emptyBridge = new DeclarativeConfigPropertiesBridgeBuilder() - .resolveInstrumentationConfig( + .buildFromInstrumentationConfig( Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig())); } @@ -45,7 +45,7 @@ private static ConfigProperties create(DeclarativeConfigPropertiesBridgeBuilder DeclarativeConfigPropertiesBridgeTest.class .getClassLoader() .getResourceAsStream("config.yaml")); - return builder.resolveInstrumentationConfig( + return builder.buildFromInstrumentationConfig( SdkConfigProvider.create(model).getInstrumentationConfig()); } @@ -124,32 +124,18 @@ void vendor() { @Test void vendorTranslation() { ConfigProperties propertiesBridge = - create( - new DeclarativeConfigPropertiesBridgeBuilder() - .addTranslation("acme", "acme.full_name")); + create(new DeclarativeConfigPropertiesBridgeBuilder().addMapping("acme", "acme.full_name")); assertThat(propertiesBridge.getBoolean("acme.preserved")).isTrue(); } - @Test - void agentCommonTranslation() { - assertThat( - create( - new DeclarativeConfigPropertiesBridgeBuilder() - .addTranslation( - "otel.instrumentation.common.default-enabled", - "common.default.enabled")) - .getBoolean("otel.instrumentation.common.default-enabled")) - .isFalse(); - } - @Test void agentTranslation() { ConfigProperties bridge = create( new DeclarativeConfigPropertiesBridgeBuilder() - .addTranslation("otel.javaagent", "agent") - .addFixedValue("otel.javaagent.debug", true) - .addFixedValue("otel.javaagent.logging", "application")); + .addMapping("otel.javaagent", "agent") + .addOverride("otel.javaagent.debug", true) + .addOverride("otel.javaagent.logging", "application")); assertThat(bridge.getBoolean("otel.javaagent.debug")).isTrue(); assertThat(bridge.getBoolean("otel.javaagent.experimental.indy")).isTrue(); diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java index 1cefdc64c..0883750d6 100644 --- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java +++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthDeclarativeConfigurationCustomizerProvider.java @@ -75,7 +75,7 @@ static void customize( static ConfigProperties getConfigProperties(OpenTelemetryConfigurationModel model) { return new DeclarativeConfigPropertiesBridgeBuilder() - .resolveInstrumentationConfig(SdkConfigProvider.create(model).getInstrumentationConfig()); + .buildFromInstrumentationConfig(SdkConfigProvider.create(model).getInstrumentationConfig()); } private static void customizeMeter( From f895a1ee2b7c7159d1a835b390164d5345392c30 Mon Sep 17 00:00:00 2001 From: otelbot <197425009+otelbot@users.noreply.github.com> Date: Fri, 15 Aug 2025 11:10:03 +0000 Subject: [PATCH 41/41] ./gradlew spotlessApply --- .../sdk/autoconfigure/ConfigPropertiesUtil.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java index eff0b7706..cef09e2c0 100644 --- a/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.java @@ -13,11 +13,11 @@ public static String propertyYamlPath(String propertyName) { } static String yamlPath(String property) { - String[] segments = DeclarativeConfigPropertiesBridge.getSegments(property); - if (segments.length == 0) { - throw new IllegalArgumentException("Invalid property: " + property); - } + String[] segments = DeclarativeConfigPropertiesBridge.getSegments(property); + if (segments.length == 0) { + throw new IllegalArgumentException("Invalid property: " + property); + } - return "'instrumentation/development' / 'java' / '" + String.join("' / '", segments) + "'"; - } + return "'instrumentation/development' / 'java' / '" + String.join("' / '", segments) + "'"; + } }