From 1f144e1dedbc212371a2ba90bc83bec25bad016a Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Sat, 13 Dec 2025 20:00:20 -0800 Subject: [PATCH 1/4] The one true config bridge --- .../ConfigPropertiesBackedConfigProvider.java | 38 ++++ ...tiesBackedDeclarativeConfigProperties.java | 207 ++++++++++++++++++ .../config/bridge/PeerServiceMapping.java | 105 +++++++++ .../internal/DeclarativeConfigUtil.java | 35 +++ .../graphql/v12_0/GraphqlSingletons.java | 44 ++-- .../graphql/v20_0/GraphqlSingletons.java | 58 ++--- .../methods/MethodInstrumentationModule.java | 32 +-- .../methods/MethodsConfig.java | 34 ++- .../ExtendedOpenTelemetrySdkWrapper.java | 30 +++ .../tooling/OpenTelemetryInstaller.java | 36 +-- 10 files changed, 532 insertions(+), 87 deletions(-) create mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesBackedConfigProvider.java create mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesBackedDeclarativeConfigProperties.java create mode 100644 declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/PeerServiceMapping.java create mode 100644 instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/DeclarativeConfigUtil.java create mode 100644 javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ExtendedOpenTelemetrySdkWrapper.java diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesBackedConfigProvider.java b/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesBackedConfigProvider.java new file mode 100644 index 000000000000..b35136987745 --- /dev/null +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesBackedConfigProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.config.bridge; + +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import javax.annotation.Nullable; + +/** + * A {@link ConfigProvider} implementation backed by {@link ConfigProperties}. + * + *

This allows instrumentations to always use {@code ExtendedOpenTelemetry.getConfigProvider()} + * regardless of whether the user started with system properties or YAML. + */ +public final class ConfigPropertiesBackedConfigProvider implements ConfigProvider { + + private final DeclarativeConfigProperties instrumentationConfig; + + public static ConfigProvider create(ConfigProperties configProperties) { + return new ConfigPropertiesBackedConfigProvider(configProperties); + } + + private ConfigPropertiesBackedConfigProvider(ConfigProperties configProperties) { + this.instrumentationConfig = + ConfigPropertiesBackedDeclarativeConfigProperties.createInstrumentationConfig( + configProperties); + } + + @Nullable + @Override + public DeclarativeConfigProperties getInstrumentationConfig() { + return instrumentationConfig; + } +} diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesBackedDeclarativeConfigProperties.java b/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesBackedDeclarativeConfigProperties.java new file mode 100644 index 000000000000..5ab0cf14677a --- /dev/null +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesBackedDeclarativeConfigProperties.java @@ -0,0 +1,207 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.config.bridge; + +import static java.util.Collections.emptySet; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nullable; + +/** + * Implementation of {@link DeclarativeConfigProperties} backed by {@link ConfigProperties}. + * + *

It tracks the navigation path and only resolves to system properties at the leaf node when a + * value is actually requested. + */ +public final class ConfigPropertiesBackedDeclarativeConfigProperties + implements DeclarativeConfigProperties { + + private static final String GENERAL_PEER_SERVICE_MAPPING = "general.peer.service_mapping"; + + private static final Map LIST_MAPPINGS; + + static { + LIST_MAPPINGS = new HashMap<>(); + LIST_MAPPINGS.put( + "general.http.client.request_captured_headers", + "otel.instrumentation.http.client.capture-request-headers"); + LIST_MAPPINGS.put( + "general.http.client.response_captured_headers", + "otel.instrumentation.http.client.capture-response-headers"); + LIST_MAPPINGS.put( + "general.http.server.request_captured_headers", + "otel.instrumentation.http.server.capture-request-headers"); + LIST_MAPPINGS.put( + "general.http.server.response_captured_headers", + "otel.instrumentation.http.server.capture-response-headers"); + } + + private final ConfigProperties configProperties; + private final List path; + + public static DeclarativeConfigProperties createInstrumentationConfig( + ConfigProperties configProperties) { + return new ConfigPropertiesBackedDeclarativeConfigProperties( + configProperties, Collections.emptyList()); + } + + private ConfigPropertiesBackedDeclarativeConfigProperties( + ConfigProperties configProperties, List path) { + this.configProperties = configProperties; + this.path = path; + } + + @Nullable + @Override + public String getString(String name) { + String fullPath = pathWithName(name); + return configProperties.getString(toPropertyKey(fullPath)); + } + + @Nullable + @Override + public Boolean getBoolean(String name) { + String fullPath = pathWithName(name); + return configProperties.getBoolean(toPropertyKey(fullPath)); + } + + @Nullable + @Override + public Integer getInt(String name) { + String fullPath = pathWithName(name); + return configProperties.getInt(toPropertyKey(fullPath)); + } + + @Nullable + @Override + public Long getLong(String name) { + String fullPath = pathWithName(name); + return configProperties.getLong(toPropertyKey(fullPath)); + } + + @Nullable + @Override + public Double getDouble(String name) { + String fullPath = pathWithName(name); + return configProperties.getDouble(toPropertyKey(fullPath)); + } + + /** + * Important: this method should return null if there is no structured child with the given name, + * but unfortunately that is not implementable on top of ConfigProperties. + * + *

This will be misleading if anyone is comparing the return value to null. + */ + @Override + public DeclarativeConfigProperties getStructured(String name) { + List newPath = new ArrayList<>(path); + newPath.add(name); + return new ConfigPropertiesBackedDeclarativeConfigProperties(configProperties, newPath); + } + + @Nullable + @Override + @SuppressWarnings("unchecked") // Safe because T is known to be String via scalarType check + public List getScalarList(String name, Class scalarType) { + if (scalarType != String.class) { + return null; + } + String fullPath = pathWithName(name); + + // Check explicit list mappings first + String mappedKey = LIST_MAPPINGS.get(fullPath); + if (mappedKey != null) { + List list = configProperties.getList(mappedKey); + if (!list.isEmpty()) { + return (List) list; + } + return null; + } + + // Standard mapping + List list = configProperties.getList(toPropertyKey(fullPath)); + if (list.isEmpty()) { + return null; + } + return (List) list; + } + + @Nullable + @Override + public List getStructuredList(String name) { + String fullPath = pathWithName(name); + if (GENERAL_PEER_SERVICE_MAPPING.equals(fullPath)) { + return PeerServiceMapping.getList(configProperties); + } + return null; + } + + @Override + public Set getPropertyKeys() { + // this is not supported when using system properties based configuration + return emptySet(); + } + + @Override + public ComponentLoader getComponentLoader() { + return configProperties.getComponentLoader(); + } + + private String pathWithName(String name) { + if (path.isEmpty()) { + return name; + } + return String.join(".", path) + "." + name; + } + + private static String toPropertyKey(String fullPath) { + String translatedPath = translatePath(fullPath); + + // Handle agent prefix: java.agent.* → otel.javaagent.* + if (translatedPath.startsWith("agent.")) { + return "otel.java" + translatedPath; + } + + // Handle jmx prefix: java.jmx.* → otel.jmx.* + if (translatedPath.startsWith("jmx.")) { + return "otel." + translatedPath; + } + + // Standard mapping + return "otel.instrumentation." + translatedPath; + } + + private static String translatePath(String path) { + StringBuilder result = new StringBuilder(); + for (String segment : path.split("\\.")) { + // Skip "java" segment - it doesn't exist in system properties + if ("java".equals(segment)) { + continue; + } + if (result.length() > 0) { + result.append("."); + } + result.append(translateName(segment)); + } + return result.toString(); + } + + private static String translateName(String name) { + if (name.endsWith("/development")) { + return "experimental." + + name.substring(0, name.length() - "/development".length()).replace('_', '-'); + } + return name.replace('_', '-'); + } +} diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/PeerServiceMapping.java b/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/PeerServiceMapping.java new file mode 100644 index 000000000000..49e86576ce20 --- /dev/null +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/PeerServiceMapping.java @@ -0,0 +1,105 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.config.bridge; + +import static java.util.Collections.emptySet; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nullable; + +final class PeerServiceMapping implements DeclarativeConfigProperties { + + private final Map fields; + private final ComponentLoader componentLoader; + + @Nullable + static List getList(ConfigProperties configProperties) { + Map map = + configProperties.getMap("otel.instrumentation.common.peer-service-mapping"); + if (map.isEmpty()) { + return null; + } + List result = new ArrayList<>(); + for (Map.Entry entry : map.entrySet()) { + Map fields = new HashMap<>(); + fields.put("peer", entry.getKey()); + fields.put("service", entry.getValue()); + result.add(new PeerServiceMapping(fields, configProperties.getComponentLoader())); + } + return result; + } + + private PeerServiceMapping(Map fields, ComponentLoader componentLoader) { + this.fields = fields; + this.componentLoader = componentLoader; + } + + @Nullable + @Override + public String getString(String name) { + return fields.get(name); + } + + @Nullable + @Override + public Boolean getBoolean(String name) { + return null; + } + + @Nullable + @Override + public Integer getInt(String name) { + return null; + } + + @Nullable + @Override + public Long getLong(String name) { + return null; + } + + @Nullable + @Override + public Double getDouble(String name) { + return null; + } + + @Nullable + @Override + public DeclarativeConfigProperties getStructured(String name) { + return null; + } + + @Nullable + @Override + public List getScalarList(String name, Class scalarType) { + return null; + } + + @Nullable + @Override + public List getStructuredList(String name) { + return null; + } + + @Override + public Set getPropertyKeys() { + // this is not supported when using system properties based configuration + return emptySet(); + } + + @Override + public ComponentLoader getComponentLoader() { + return componentLoader; + } +} diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/DeclarativeConfigUtil.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/DeclarativeConfigUtil.java new file mode 100644 index 000000000000..5dce405b98de --- /dev/null +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/DeclarativeConfigUtil.java @@ -0,0 +1,35 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.incubator.config.internal; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public final class DeclarativeConfigUtil { + + // this is a temporary convenience until getConfigProvider is available on OpenTelemetry + public static DeclarativeConfigProperties getStructured( + OpenTelemetry openTelemetry, String name, DeclarativeConfigProperties defaultValue) { + + if (!(openTelemetry instanceof ExtendedOpenTelemetry)) { + return defaultValue; + } + ExtendedOpenTelemetry extendedOpenTelemetry = (ExtendedOpenTelemetry) openTelemetry; + DeclarativeConfigProperties instrumentationConfig = + extendedOpenTelemetry.getConfigProvider().getInstrumentationConfig(); + if (instrumentationConfig == null) { + return defaultValue; + } + return instrumentationConfig.getStructured(name, defaultValue); + } + + private DeclarativeConfigUtil() {} +} diff --git a/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java b/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java index 79e0130d3129..09973afa467f 100644 --- a/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java +++ b/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java @@ -5,31 +5,39 @@ package io.opentelemetry.javaagent.instrumentation.graphql.v12_0; +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; + import graphql.execution.instrumentation.Instrumentation; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.instrumentation.api.incubator.config.internal.DeclarativeConfigUtil; import io.opentelemetry.instrumentation.graphql.internal.InstrumentationUtil; import io.opentelemetry.instrumentation.graphql.v12_0.GraphQLTelemetry; -import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; public final class GraphqlSingletons { - private static final boolean CAPTURE_QUERY = - AgentInstrumentationConfig.get() - .getBoolean("otel.instrumentation.graphql.capture-query", true); - private static final boolean QUERY_SANITIZATION_ENABLED = - AgentInstrumentationConfig.get() - .getBoolean("otel.instrumentation.graphql.query-sanitizer.enabled", true); - private static final boolean ADD_OPERATION_NAME_TO_SPAN_NAME = - AgentInstrumentationConfig.get() - .getBoolean( - "otel.instrumentation.graphql.add-operation-name-to-span-name.enabled", false); - - private static final GraphQLTelemetry TELEMETRY = - GraphQLTelemetry.builder(GlobalOpenTelemetry.get()) - .setCaptureQuery(CAPTURE_QUERY) - .setSanitizeQuery(QUERY_SANITIZATION_ENABLED) - .setAddOperationNameToSpanName(ADD_OPERATION_NAME_TO_SPAN_NAME) - .build(); + private static final GraphQLTelemetry TELEMETRY; + + static { + DeclarativeConfigProperties graphqlConfig = + DeclarativeConfigUtil.getStructured(GlobalOpenTelemetry.get(), "java", empty()) + .getStructured("graphql", empty()); + + boolean captureQuery = graphqlConfig.getBoolean("capture_query", true); + boolean sanitizeQuery = + graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled", true); + boolean addOperationNameToSpanName = + graphqlConfig + .getStructured("add_operation_name_to_span_name", empty()) + .getBoolean("enabled", false); + + TELEMETRY = + GraphQLTelemetry.builder(GlobalOpenTelemetry.get()) + .setCaptureQuery(captureQuery) + .setSanitizeQuery(sanitizeQuery) + .setAddOperationNameToSpanName(addOperationNameToSpanName) + .build(); + } private GraphqlSingletons() {} diff --git a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java index 99845529f985..2006d0b11678 100644 --- a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java +++ b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java @@ -5,39 +5,45 @@ package io.opentelemetry.javaagent.instrumentation.graphql.v20_0; +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; + import graphql.execution.instrumentation.Instrumentation; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.instrumentation.api.incubator.config.internal.DeclarativeConfigUtil; import io.opentelemetry.instrumentation.graphql.internal.InstrumentationUtil; import io.opentelemetry.instrumentation.graphql.v20_0.GraphQLTelemetry; -import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; public final class GraphqlSingletons { - private static final boolean CAPTURE_QUERY = - AgentInstrumentationConfig.get() - .getBoolean("otel.instrumentation.graphql.capture-query", true); - private static final boolean QUERY_SANITIZATION_ENABLED = - AgentInstrumentationConfig.get() - .getBoolean("otel.instrumentation.graphql.query-sanitizer.enabled", true); - private static final boolean DATA_FETCHER_ENABLED = - AgentInstrumentationConfig.get() - .getBoolean("otel.instrumentation.graphql.data-fetcher.enabled", false); - private static final boolean TRIVIAL_DATA_FETCHER_ENABLED = - AgentInstrumentationConfig.get() - .getBoolean("otel.instrumentation.graphql.trivial-data-fetcher.enabled", false); - private static final boolean ADD_OPERATION_NAME_TO_SPAN_NAME = - AgentInstrumentationConfig.get() - .getBoolean( - "otel.instrumentation.graphql.add-operation-name-to-span-name.enabled", false); - - private static final GraphQLTelemetry TELEMETRY = - GraphQLTelemetry.builder(GlobalOpenTelemetry.get()) - .setCaptureQuery(CAPTURE_QUERY) - .setSanitizeQuery(QUERY_SANITIZATION_ENABLED) - .setDataFetcherInstrumentationEnabled(DATA_FETCHER_ENABLED) - .setTrivialDataFetcherInstrumentationEnabled(TRIVIAL_DATA_FETCHER_ENABLED) - .setAddOperationNameToSpanName(ADD_OPERATION_NAME_TO_SPAN_NAME) - .build(); + private static final GraphQLTelemetry TELEMETRY; + + static { + DeclarativeConfigProperties graphqlConfig = + DeclarativeConfigUtil.getStructured(GlobalOpenTelemetry.get(), "java", empty()) + .getStructured("graphql", empty()); + + boolean captureQuery = graphqlConfig.getBoolean("capture_query", true); + boolean sanitizeQuery = + graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled", true); + boolean dataFetcherEnabled = + graphqlConfig.getStructured("data_fetcher", empty()).getBoolean("enabled", false); + boolean trivialDataFetcherEnabled = + graphqlConfig.getStructured("trivial_data_fetcher", empty()).getBoolean("enabled", false); + boolean addOperationNameToSpanName = + graphqlConfig + .getStructured("add_operation_name_to_span_name", empty()) + .getBoolean("enabled", false); + + TELEMETRY = + GraphQLTelemetry.builder(GlobalOpenTelemetry.get()) + .setCaptureQuery(captureQuery) + .setSanitizeQuery(sanitizeQuery) + .setDataFetcherInstrumentationEnabled(dataFetcherEnabled) + .setTrivialDataFetcherInstrumentationEnabled(trivialDataFetcherEnabled) + .setAddOperationNameToSpanName(addOperationNameToSpanName) + .build(); + } private GraphqlSingletons() {} diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java index 71fe619da4db..149c3cd8f81b 100644 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java @@ -5,29 +5,24 @@ package io.opentelemetry.javaagent.instrumentation.methods; +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import com.google.auto.service.AutoService; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; +import io.opentelemetry.instrumentation.api.incubator.config.internal.DeclarativeConfigUtil; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; -import io.opentelemetry.javaagent.tooling.config.MethodsConfigurationParser; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; @AutoService(InstrumentationModule.class) public class MethodInstrumentationModule extends InstrumentationModule implements ExperimentalInstrumentationModule { - private static final String TRACE_METHODS_CONFIG = "otel.instrumentation.methods.include"; - private final List typeInstrumentations; public MethodInstrumentationModule() { @@ -36,11 +31,10 @@ public MethodInstrumentationModule() { } private static List createInstrumentations() { - InstrumentationConfig config = AgentInstrumentationConfig.get(); List list = - config.isDeclarative() - ? MethodsConfig.parseDeclarativeConfig(config.getDeclarativeConfig("methods")) - : parseConfigProperties(); + MethodsConfig.parse( + DeclarativeConfigUtil.getStructured(GlobalOpenTelemetry.get(), "java", empty()) + .getStructured("methods", empty())); // ensure that there is at least one instrumentation so that muzzle reference collection could // work if (list.isEmpty()) { @@ -50,20 +44,6 @@ private static List createInstrumentations() { return list; } - private static List parseConfigProperties() { - Map> classMethodsToTrace = - MethodsConfigurationParser.parse( - AgentInstrumentationConfig.get().getString(TRACE_METHODS_CONFIG)); - - return classMethodsToTrace.entrySet().stream() - .filter(e -> !e.getValue().isEmpty()) - .map( - e -> - new MethodInstrumentation( - e.getKey(), singletonMap(SpanKind.INTERNAL, e.getValue()))) - .collect(Collectors.toList()); - } - @Override public List typeInstrumentations() { return typeInstrumentations; diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodsConfig.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodsConfig.java index 692ede856414..baa47a193e0b 100644 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodsConfig.java +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodsConfig.java @@ -6,16 +6,19 @@ package io.opentelemetry.javaagent.instrumentation.methods; import static java.util.Collections.emptyList; +import static java.util.Collections.singletonMap; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.tooling.config.MethodsConfigurationParser; import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -27,10 +30,22 @@ public class MethodsConfig { private MethodsConfig() {} - static List parseDeclarativeConfig(DeclarativeConfigProperties methods) { - return methods.getStructuredList("include", emptyList()).stream() - .flatMap(MethodsConfig::parseMethodInstrumentation) - .collect(Collectors.toList()); + static List parse(DeclarativeConfigProperties methods) { + // First try structured declarative config (YAML format) + List includeList = methods.getStructuredList("include"); + if (includeList != null) { + return includeList.stream() + .flatMap(MethodsConfig::parseMethodInstrumentation) + .collect(Collectors.toList()); + } + + // Fall back to old string property format + String include = methods.getString("include"); + if (include != null) { + return parseConfigString(include); + } + + return emptyList(); } private static Stream parseMethodInstrumentation( @@ -74,4 +89,15 @@ private static Stream parseMethodInstrumentation( private static boolean isNullOrEmpty(String s) { return s == null || s.isEmpty(); } + + private static List parseConfigString(String include) { + Map> classMethodsToTrace = MethodsConfigurationParser.parse(include); + return classMethodsToTrace.entrySet().stream() + .filter(e -> !e.getValue().isEmpty()) + .map( + e -> + new MethodInstrumentation( + e.getKey(), singletonMap(SpanKind.INTERNAL, e.getValue()))) + .collect(Collectors.toList()); + } } diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ExtendedOpenTelemetrySdkWrapper.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ExtendedOpenTelemetrySdkWrapper.java new file mode 100644 index 000000000000..eef2c357b590 --- /dev/null +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ExtendedOpenTelemetrySdkWrapper.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling; + +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.sdk.OpenTelemetrySdk; + +final class ExtendedOpenTelemetrySdkWrapper extends OpenTelemetrySdk + implements ExtendedOpenTelemetry { + + private final ConfigProvider configProvider; + + ExtendedOpenTelemetrySdkWrapper(OpenTelemetrySdk delegate, ConfigProvider configProvider) { + super( + delegate.getSdkTracerProvider(), + delegate.getSdkMeterProvider(), + delegate.getSdkLoggerProvider(), + delegate.getPropagators()); + this.configProvider = configProvider; + } + + @Override + public ConfigProvider getConfigProvider() { + return configProvider; + } +} diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java index ff7147ef44bb..5a38f838e932 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java @@ -7,8 +7,10 @@ import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.instrumentation.config.bridge.ConfigPropertiesBackedConfigProvider; import io.opentelemetry.instrumentation.config.bridge.DeclarativeConfigPropertiesBridgeBuilder; import io.opentelemetry.javaagent.bootstrap.OpenTelemetrySdkAccess; import io.opentelemetry.javaagent.tooling.config.EarlyInitAgentConfig; @@ -34,26 +36,34 @@ public static AutoConfiguredOpenTelemetrySdk installOpenTelemetrySdk( AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = AutoConfiguredOpenTelemetrySdk.builder() - .setResultAsGlobal() + // Don't use setResultAsGlobal() - we need to wrap the SDK before setting as global .setServiceClassLoader(extensionClassLoader) .build(); ConfigProvider configProvider = AutoConfigureUtil.getConfigProvider(autoConfiguredSdk); OpenTelemetrySdk sdk = autoConfiguredSdk.getOpenTelemetrySdk(); + ConfigProperties configProperties = AutoConfigureUtil.getConfig(autoConfiguredSdk); + if (configProvider == null && configProperties != null) { + // Provide a fake declarative configuration based on config properties + // so that declarative configuration API can be used everywhere + configProvider = ConfigPropertiesBackedConfigProvider.create(configProperties); + sdk = new ExtendedOpenTelemetrySdkWrapper(sdk, configProvider); + } else if (configProperties == null && configProvider != null) { + // Provide a fake ConfigProperties until we have migrated all runtime configuration + // access to use declarative configuration API + configProperties = getDeclarativeConfigBridgedProperties(earlyConfig, configProvider); + } else { + throw new IllegalStateException( + "Exactly one of configProvider or configProperties must be non-null"); + } setForceFlush(sdk); + GlobalOpenTelemetry.set(sdk); - if (configProvider != null) { - // We create a new instance of AutoConfiguredOpenTelemetrySdk, which has a ConfigProperties - // instance that can be used to read properties from the configuration file. - // This allows most instrumentations to be unaware of which configuration style is used. - return SdkAutoconfigureAccess.create( - sdk, - SdkAutoconfigureAccess.getResource(autoConfiguredSdk), - getDeclarativeConfigBridgedProperties(earlyConfig, configProvider), - configProvider); - } - - return autoConfiguredSdk; + return SdkAutoconfigureAccess.create( + sdk, + SdkAutoconfigureAccess.getResource(autoConfiguredSdk), + configProperties, + configProvider); } // Visible for testing From 3baf7492b7486cb964c782ffcf88848937ccaf51 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 15 Dec 2025 12:13:22 -0800 Subject: [PATCH 2/4] easier to read --- .../graphql/v12_0/GraphqlSingletons.java | 64 ++++++++++---- .../graphql/v20_0/GraphqlSingletons.java | 87 ++++++++++++++----- 2 files changed, 116 insertions(+), 35 deletions(-) diff --git a/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java b/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java index 09973afa467f..8c6a0d0b721d 100644 --- a/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java +++ b/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java @@ -9,33 +9,26 @@ import graphql.execution.instrumentation.Instrumentation; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.instrumentation.api.incubator.config.internal.DeclarativeConfigUtil; import io.opentelemetry.instrumentation.graphql.internal.InstrumentationUtil; import io.opentelemetry.instrumentation.graphql.v12_0.GraphQLTelemetry; +import javax.annotation.Nullable; public final class GraphqlSingletons { private static final GraphQLTelemetry TELEMETRY; static { - DeclarativeConfigProperties graphqlConfig = - DeclarativeConfigUtil.getStructured(GlobalOpenTelemetry.get(), "java", empty()) - .getStructured("graphql", empty()); - - boolean captureQuery = graphqlConfig.getBoolean("capture_query", true); - boolean sanitizeQuery = - graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled", true); - boolean addOperationNameToSpanName = - graphqlConfig - .getStructured("add_operation_name_to_span_name", empty()) - .getBoolean("enabled", false); + OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); + Configuration config = new Configuration(openTelemetry); TELEMETRY = - GraphQLTelemetry.builder(GlobalOpenTelemetry.get()) - .setCaptureQuery(captureQuery) - .setSanitizeQuery(sanitizeQuery) - .setAddOperationNameToSpanName(addOperationNameToSpanName) + GraphQLTelemetry.builder(openTelemetry) + .setCaptureQuery(config.captureQuery(true)) + .setSanitizeQuery(config.querySanitizerEnabled(true)) + .setAddOperationNameToSpanName(config.addOperationNameToSpanName(false)) .build(); } @@ -45,4 +38,45 @@ public static Instrumentation addInstrumentation(Instrumentation instrumentation Instrumentation ourInstrumentation = TELEMETRY.newInstrumentation(); return InstrumentationUtil.addInstrumentation(instrumentation, ourInstrumentation); } + + // instrumentation/development: + // java: + // graphql: + // capture_query: [boolean] + // query_sanitizer: + // enabled: [boolean] + // add_operation_name_to_span_name: + // enabled: [boolean] + private static final class Configuration { + + @Nullable private final Boolean captureQuery; + @Nullable private final Boolean querySanitizerEnabled; + @Nullable private final Boolean addOperationNameToSpanName; + + Configuration(OpenTelemetry openTelemetry) { + DeclarativeConfigProperties graphqlConfig = + DeclarativeConfigUtil.getStructured(openTelemetry, "java", empty()) + .getStructured("graphql", empty()); + + this.captureQuery = graphqlConfig.getBoolean("capture_query"); + this.querySanitizerEnabled = + graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled"); + this.addOperationNameToSpanName = + graphqlConfig + .getStructured("add_operation_name_to_span_name", empty()) + .getBoolean("enabled"); + } + + boolean captureQuery(boolean defaultValue) { + return captureQuery != null ? captureQuery : defaultValue; + } + + boolean querySanitizerEnabled(boolean defaultValue) { + return querySanitizerEnabled != null ? querySanitizerEnabled : defaultValue; + } + + boolean addOperationNameToSpanName(boolean defaultValue) { + return addOperationNameToSpanName != null ? addOperationNameToSpanName : defaultValue; + } + } } diff --git a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java index 2006d0b11678..2aa900bbdc4c 100644 --- a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java +++ b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java @@ -9,39 +9,27 @@ import graphql.execution.instrumentation.Instrumentation; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.instrumentation.api.incubator.config.internal.DeclarativeConfigUtil; import io.opentelemetry.instrumentation.graphql.internal.InstrumentationUtil; import io.opentelemetry.instrumentation.graphql.v20_0.GraphQLTelemetry; +import javax.annotation.Nullable; public final class GraphqlSingletons { private static final GraphQLTelemetry TELEMETRY; static { - DeclarativeConfigProperties graphqlConfig = - DeclarativeConfigUtil.getStructured(GlobalOpenTelemetry.get(), "java", empty()) - .getStructured("graphql", empty()); - - boolean captureQuery = graphqlConfig.getBoolean("capture_query", true); - boolean sanitizeQuery = - graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled", true); - boolean dataFetcherEnabled = - graphqlConfig.getStructured("data_fetcher", empty()).getBoolean("enabled", false); - boolean trivialDataFetcherEnabled = - graphqlConfig.getStructured("trivial_data_fetcher", empty()).getBoolean("enabled", false); - boolean addOperationNameToSpanName = - graphqlConfig - .getStructured("add_operation_name_to_span_name", empty()) - .getBoolean("enabled", false); + Configuration config = new Configuration(GlobalOpenTelemetry.get()); TELEMETRY = GraphQLTelemetry.builder(GlobalOpenTelemetry.get()) - .setCaptureQuery(captureQuery) - .setSanitizeQuery(sanitizeQuery) - .setDataFetcherInstrumentationEnabled(dataFetcherEnabled) - .setTrivialDataFetcherInstrumentationEnabled(trivialDataFetcherEnabled) - .setAddOperationNameToSpanName(addOperationNameToSpanName) + .setCaptureQuery(config.captureQuery(true)) + .setSanitizeQuery(config.sanitizeQuery(true)) + .setDataFetcherInstrumentationEnabled(config.dataFetcherEnabled(false)) + .setTrivialDataFetcherInstrumentationEnabled(config.trivialDataFetcherEnabled(false)) + .setAddOperationNameToSpanName(config.addOperationNameToSpanName(false)) .build(); } @@ -51,4 +39,63 @@ public static Instrumentation addInstrumentation(Instrumentation instrumentation Instrumentation ourInstrumentation = TELEMETRY.newInstrumentation(); return InstrumentationUtil.addInstrumentation(instrumentation, ourInstrumentation); } + + // instrumentation/development: + // java: + // graphql: + // capture_query: [boolean] + // query_sanitizer: + // enabled: [boolean] + // data_fetcher: + // enabled: [boolean] + // trivial_data_fetcher: + // enabled: [boolean] + // add_operation_name_to_span_name: + // enabled: [boolean] + private static final class Configuration { + + @Nullable private final Boolean captureQuery; + @Nullable private final Boolean sanitizeQuery; + @Nullable private final Boolean dataFetcherEnabled; + @Nullable private final Boolean trivialDataFetcherEnabled; + @Nullable private final Boolean addOperationNameToSpanName; + + Configuration(OpenTelemetry openTelemetry) { + DeclarativeConfigProperties graphqlConfig = + DeclarativeConfigUtil.getStructured(openTelemetry, "java", empty()) + .getStructured("graphql", empty()); + + this.captureQuery = graphqlConfig.getBoolean("capture_query"); + this.sanitizeQuery = + graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled"); + this.dataFetcherEnabled = + graphqlConfig.getStructured("data_fetcher", empty()).getBoolean("enabled"); + this.trivialDataFetcherEnabled = + graphqlConfig.getStructured("trivial_data_fetcher", empty()).getBoolean("enabled"); + this.addOperationNameToSpanName = + graphqlConfig + .getStructured("add_operation_name_to_span_name", empty()) + .getBoolean("enabled"); + } + + boolean captureQuery(boolean defaultValue) { + return captureQuery != null ? captureQuery : defaultValue; + } + + boolean sanitizeQuery(boolean defaultValue) { + return sanitizeQuery != null ? sanitizeQuery : defaultValue; + } + + boolean dataFetcherEnabled(boolean defaultValue) { + return dataFetcherEnabled != null ? dataFetcherEnabled : defaultValue; + } + + boolean trivialDataFetcherEnabled(boolean defaultValue) { + return trivialDataFetcherEnabled != null ? trivialDataFetcherEnabled : defaultValue; + } + + boolean addOperationNameToSpanName(boolean defaultValue) { + return addOperationNameToSpanName != null ? addOperationNameToSpanName : defaultValue; + } + } } From 7653f0fffa995b2e9f36e0af782e0c26b875b2d2 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 15 Dec 2025 15:00:58 -0800 Subject: [PATCH 3/4] Move defaults inside of configuration model --- .../internal/DeclarativeConfigUtil.java | 35 --------- .../graphql/v12_0/GraphqlSingletons.java | 54 ++++++------- .../graphql/v20_0/GraphqlSingletons.java | 78 ++++++++----------- ...dsConfig.java => MethodConfiguration.java} | 32 ++++++-- .../methods/MethodInstrumentationModule.java | 8 +- 5 files changed, 85 insertions(+), 122 deletions(-) delete mode 100644 instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/DeclarativeConfigUtil.java rename instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/{MethodsConfig.java => MethodConfiguration.java} (71%) diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/DeclarativeConfigUtil.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/DeclarativeConfigUtil.java deleted file mode 100644 index 5dce405b98de..000000000000 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/DeclarativeConfigUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.api.incubator.config.internal; - -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; - -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ -public final class DeclarativeConfigUtil { - - // this is a temporary convenience until getConfigProvider is available on OpenTelemetry - public static DeclarativeConfigProperties getStructured( - OpenTelemetry openTelemetry, String name, DeclarativeConfigProperties defaultValue) { - - if (!(openTelemetry instanceof ExtendedOpenTelemetry)) { - return defaultValue; - } - ExtendedOpenTelemetry extendedOpenTelemetry = (ExtendedOpenTelemetry) openTelemetry; - DeclarativeConfigProperties instrumentationConfig = - extendedOpenTelemetry.getConfigProvider().getInstrumentationConfig(); - if (instrumentationConfig == null) { - return defaultValue; - } - return instrumentationConfig.getStructured(name, defaultValue); - } - - private DeclarativeConfigUtil() {} -} diff --git a/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java b/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java index 8c6a0d0b721d..4b54e27bfb89 100644 --- a/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java +++ b/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java @@ -10,11 +10,10 @@ import graphql.execution.instrumentation.Instrumentation; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.instrumentation.api.incubator.config.internal.DeclarativeConfigUtil; import io.opentelemetry.instrumentation.graphql.internal.InstrumentationUtil; import io.opentelemetry.instrumentation.graphql.v12_0.GraphQLTelemetry; -import javax.annotation.Nullable; public final class GraphqlSingletons { @@ -26,9 +25,9 @@ public final class GraphqlSingletons { TELEMETRY = GraphQLTelemetry.builder(openTelemetry) - .setCaptureQuery(config.captureQuery(true)) - .setSanitizeQuery(config.querySanitizerEnabled(true)) - .setAddOperationNameToSpanName(config.addOperationNameToSpanName(false)) + .setCaptureQuery(config.captureQuery) + .setSanitizeQuery(config.querySanitizerEnabled) + .setAddOperationNameToSpanName(config.addOperationNameToSpanName) .build(); } @@ -42,41 +41,36 @@ public static Instrumentation addInstrumentation(Instrumentation instrumentation // instrumentation/development: // java: // graphql: - // capture_query: [boolean] + // capture_query: true // query_sanitizer: - // enabled: [boolean] + // enabled: true // add_operation_name_to_span_name: - // enabled: [boolean] + // enabled: false private static final class Configuration { - @Nullable private final Boolean captureQuery; - @Nullable private final Boolean querySanitizerEnabled; - @Nullable private final Boolean addOperationNameToSpanName; + private final boolean captureQuery; + private final boolean querySanitizerEnabled; + private final boolean addOperationNameToSpanName; Configuration(OpenTelemetry openTelemetry) { - DeclarativeConfigProperties graphqlConfig = - DeclarativeConfigUtil.getStructured(openTelemetry, "java", empty()) - .getStructured("graphql", empty()); - - this.captureQuery = graphqlConfig.getBoolean("capture_query"); + DeclarativeConfigProperties javaConfig = empty(); + if (openTelemetry instanceof ExtendedOpenTelemetry) { + ExtendedOpenTelemetry extendedOpenTelemetry = (ExtendedOpenTelemetry) openTelemetry; + DeclarativeConfigProperties instrumentationConfig = + extendedOpenTelemetry.getConfigProvider().getInstrumentationConfig(); + if (instrumentationConfig != null) { + javaConfig = instrumentationConfig.getStructured("java", empty()); + } + } + DeclarativeConfigProperties graphqlConfig = javaConfig.getStructured("graphql", empty()); + + this.captureQuery = graphqlConfig.getBoolean("capture_query", true); this.querySanitizerEnabled = - graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled"); + graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled", true); this.addOperationNameToSpanName = graphqlConfig .getStructured("add_operation_name_to_span_name", empty()) - .getBoolean("enabled"); - } - - boolean captureQuery(boolean defaultValue) { - return captureQuery != null ? captureQuery : defaultValue; - } - - boolean querySanitizerEnabled(boolean defaultValue) { - return querySanitizerEnabled != null ? querySanitizerEnabled : defaultValue; - } - - boolean addOperationNameToSpanName(boolean defaultValue) { - return addOperationNameToSpanName != null ? addOperationNameToSpanName : defaultValue; + .getBoolean("enabled", false); } } } diff --git a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java index 2aa900bbdc4c..5a99bd256cd9 100644 --- a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java +++ b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java @@ -10,11 +10,10 @@ import graphql.execution.instrumentation.Instrumentation; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.instrumentation.api.incubator.config.internal.DeclarativeConfigUtil; import io.opentelemetry.instrumentation.graphql.internal.InstrumentationUtil; import io.opentelemetry.instrumentation.graphql.v20_0.GraphQLTelemetry; -import javax.annotation.Nullable; public final class GraphqlSingletons { @@ -25,11 +24,11 @@ public final class GraphqlSingletons { TELEMETRY = GraphQLTelemetry.builder(GlobalOpenTelemetry.get()) - .setCaptureQuery(config.captureQuery(true)) - .setSanitizeQuery(config.sanitizeQuery(true)) - .setDataFetcherInstrumentationEnabled(config.dataFetcherEnabled(false)) - .setTrivialDataFetcherInstrumentationEnabled(config.trivialDataFetcherEnabled(false)) - .setAddOperationNameToSpanName(config.addOperationNameToSpanName(false)) + .setCaptureQuery(config.captureQuery) + .setSanitizeQuery(config.sanitizeQuery) + .setDataFetcherInstrumentationEnabled(config.dataFetcherEnabled) + .setTrivialDataFetcherInstrumentationEnabled(config.trivialDataFetcherEnabled) + .setAddOperationNameToSpanName(config.addOperationNameToSpanName) .build(); } @@ -43,59 +42,46 @@ public static Instrumentation addInstrumentation(Instrumentation instrumentation // instrumentation/development: // java: // graphql: - // capture_query: [boolean] + // capture_query: true // query_sanitizer: - // enabled: [boolean] + // enabled: true // data_fetcher: - // enabled: [boolean] + // enabled: false // trivial_data_fetcher: - // enabled: [boolean] + // enabled: false // add_operation_name_to_span_name: - // enabled: [boolean] + // enabled: false private static final class Configuration { - @Nullable private final Boolean captureQuery; - @Nullable private final Boolean sanitizeQuery; - @Nullable private final Boolean dataFetcherEnabled; - @Nullable private final Boolean trivialDataFetcherEnabled; - @Nullable private final Boolean addOperationNameToSpanName; + private final boolean captureQuery; + private final boolean sanitizeQuery; + private final boolean dataFetcherEnabled; + private final boolean trivialDataFetcherEnabled; + private final boolean addOperationNameToSpanName; Configuration(OpenTelemetry openTelemetry) { - DeclarativeConfigProperties graphqlConfig = - DeclarativeConfigUtil.getStructured(openTelemetry, "java", empty()) - .getStructured("graphql", empty()); - - this.captureQuery = graphqlConfig.getBoolean("capture_query"); + DeclarativeConfigProperties javaConfig = empty(); + if (openTelemetry instanceof ExtendedOpenTelemetry) { + ExtendedOpenTelemetry extendedOpenTelemetry = (ExtendedOpenTelemetry) openTelemetry; + DeclarativeConfigProperties instrumentationConfig = + extendedOpenTelemetry.getConfigProvider().getInstrumentationConfig(); + if (instrumentationConfig != null) { + javaConfig = instrumentationConfig.getStructured("java", empty()); + } + } + DeclarativeConfigProperties graphqlConfig = javaConfig.getStructured("graphql", empty()); + + this.captureQuery = graphqlConfig.getBoolean("capture_query", true); this.sanitizeQuery = - graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled"); + graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled", true); this.dataFetcherEnabled = - graphqlConfig.getStructured("data_fetcher", empty()).getBoolean("enabled"); + graphqlConfig.getStructured("data_fetcher", empty()).getBoolean("enabled", false); this.trivialDataFetcherEnabled = - graphqlConfig.getStructured("trivial_data_fetcher", empty()).getBoolean("enabled"); + graphqlConfig.getStructured("trivial_data_fetcher", empty()).getBoolean("enabled", false); this.addOperationNameToSpanName = graphqlConfig .getStructured("add_operation_name_to_span_name", empty()) - .getBoolean("enabled"); - } - - boolean captureQuery(boolean defaultValue) { - return captureQuery != null ? captureQuery : defaultValue; - } - - boolean sanitizeQuery(boolean defaultValue) { - return sanitizeQuery != null ? sanitizeQuery : defaultValue; - } - - boolean dataFetcherEnabled(boolean defaultValue) { - return dataFetcherEnabled != null ? dataFetcherEnabled : defaultValue; - } - - boolean trivialDataFetcherEnabled(boolean defaultValue) { - return trivialDataFetcherEnabled != null ? trivialDataFetcherEnabled : defaultValue; - } - - boolean addOperationNameToSpanName(boolean defaultValue) { - return addOperationNameToSpanName != null ? addOperationNameToSpanName : defaultValue; + .getBoolean("enabled", false); } } } diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodsConfig.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodConfiguration.java similarity index 71% rename from instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodsConfig.java rename to instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodConfiguration.java index baa47a193e0b..4565ca08bbe0 100644 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodsConfig.java +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodConfiguration.java @@ -5,9 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.methods; +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; import static java.util.Collections.emptyList; import static java.util.Collections.singletonMap; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; @@ -24,18 +27,37 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public class MethodsConfig { +public class MethodConfiguration { - private static final Logger logger = Logger.getLogger(MethodsConfig.class.getName()); + private static final Logger logger = Logger.getLogger(MethodConfiguration.class.getName()); - private MethodsConfig() {} + private final List typeInstrumentations; - static List parse(DeclarativeConfigProperties methods) { + MethodConfiguration(OpenTelemetry openTelemetry) { + DeclarativeConfigProperties javaConfig = empty(); + if (openTelemetry instanceof ExtendedOpenTelemetry) { + ExtendedOpenTelemetry extendedOpenTelemetry = (ExtendedOpenTelemetry) openTelemetry; + DeclarativeConfigProperties instrumentationConfig = + extendedOpenTelemetry.getConfigProvider().getInstrumentationConfig(); + if (instrumentationConfig != null) { + javaConfig = instrumentationConfig.getStructured("java", empty()); + } + } + DeclarativeConfigProperties methodsConfig = javaConfig.getStructured("methods", empty()); + + this.typeInstrumentations = parse(methodsConfig); + } + + List typeInstrumentations() { + return typeInstrumentations; + } + + private static List parse(DeclarativeConfigProperties methods) { // First try structured declarative config (YAML format) List includeList = methods.getStructuredList("include"); if (includeList != null) { return includeList.stream() - .flatMap(MethodsConfig::parseMethodInstrumentation) + .flatMap(MethodConfiguration::parseMethodInstrumentation) .collect(Collectors.toList()); } diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java index 149c3cd8f81b..0d3f7cb79429 100644 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java @@ -5,7 +5,6 @@ package io.opentelemetry.javaagent.instrumentation.methods; -import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; @@ -13,7 +12,6 @@ import com.google.auto.service.AutoService; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.instrumentation.api.incubator.config.internal.DeclarativeConfigUtil; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; @@ -31,10 +29,8 @@ public MethodInstrumentationModule() { } private static List createInstrumentations() { - List list = - MethodsConfig.parse( - DeclarativeConfigUtil.getStructured(GlobalOpenTelemetry.get(), "java", empty()) - .getStructured("methods", empty())); + MethodConfiguration config = new MethodConfiguration(GlobalOpenTelemetry.get()); + List list = config.typeInstrumentations(); // ensure that there is at least one instrumentation so that muzzle reference collection could // work if (list.isEmpty()) { From 1add1a9ddbc1face23a7a2514840a19beab2af16 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 15 Dec 2025 15:30:52 -0800 Subject: [PATCH 4/4] small reorder --- .../instrumentation/graphql/v12_0/GraphqlSingletons.java | 4 ++-- .../instrumentation/graphql/v20_0/GraphqlSingletons.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java b/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java index 4b54e27bfb89..fe75237fa81f 100644 --- a/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java +++ b/instrumentation/graphql-java/graphql-java-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v12_0/GraphqlSingletons.java @@ -31,8 +31,6 @@ public final class GraphqlSingletons { .build(); } - private GraphqlSingletons() {} - public static Instrumentation addInstrumentation(Instrumentation instrumentation) { Instrumentation ourInstrumentation = TELEMETRY.newInstrumentation(); return InstrumentationUtil.addInstrumentation(instrumentation, ourInstrumentation); @@ -73,4 +71,6 @@ private static final class Configuration { .getBoolean("enabled", false); } } + + private GraphqlSingletons() {} } diff --git a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java index 5a99bd256cd9..84a9dbafb601 100644 --- a/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java +++ b/instrumentation/graphql-java/graphql-java-20.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/graphql/v20_0/GraphqlSingletons.java @@ -32,8 +32,6 @@ public final class GraphqlSingletons { .build(); } - private GraphqlSingletons() {} - public static Instrumentation addInstrumentation(Instrumentation instrumentation) { Instrumentation ourInstrumentation = TELEMETRY.newInstrumentation(); return InstrumentationUtil.addInstrumentation(instrumentation, ourInstrumentation); @@ -84,4 +82,6 @@ private static final class Configuration { .getBoolean("enabled", false); } } + + private GraphqlSingletons() {} }