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/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..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
@@ -5,36 +5,72 @@
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.OpenTelemetry;
+import io.opentelemetry.api.incubator.ExtendedOpenTelemetry;
+import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
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;
- private GraphqlSingletons() {}
+ static {
+ OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
+ Configuration config = new Configuration(openTelemetry);
+
+ TELEMETRY =
+ GraphQLTelemetry.builder(openTelemetry)
+ .setCaptureQuery(config.captureQuery)
+ .setSanitizeQuery(config.querySanitizerEnabled)
+ .setAddOperationNameToSpanName(config.addOperationNameToSpanName)
+ .build();
+ }
public static Instrumentation addInstrumentation(Instrumentation instrumentation) {
Instrumentation ourInstrumentation = TELEMETRY.newInstrumentation();
return InstrumentationUtil.addInstrumentation(instrumentation, ourInstrumentation);
}
+
+ // instrumentation/development:
+ // java:
+ // graphql:
+ // capture_query: true
+ // query_sanitizer:
+ // enabled: true
+ // add_operation_name_to_span_name:
+ // enabled: false
+ private static final class Configuration {
+
+ private final boolean captureQuery;
+ private final boolean querySanitizerEnabled;
+ private final boolean addOperationNameToSpanName;
+
+ Configuration(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 graphqlConfig = javaConfig.getStructured("graphql", empty());
+
+ this.captureQuery = graphqlConfig.getBoolean("capture_query", true);
+ this.querySanitizerEnabled =
+ graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled", true);
+ this.addOperationNameToSpanName =
+ graphqlConfig
+ .getStructured("add_operation_name_to_span_name", empty())
+ .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 99845529f985..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
@@ -5,44 +5,83 @@
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.OpenTelemetry;
+import io.opentelemetry.api.incubator.ExtendedOpenTelemetry;
+import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
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;
- private GraphqlSingletons() {}
+ static {
+ Configuration config = new Configuration(GlobalOpenTelemetry.get());
+
+ TELEMETRY =
+ GraphQLTelemetry.builder(GlobalOpenTelemetry.get())
+ .setCaptureQuery(config.captureQuery)
+ .setSanitizeQuery(config.sanitizeQuery)
+ .setDataFetcherInstrumentationEnabled(config.dataFetcherEnabled)
+ .setTrivialDataFetcherInstrumentationEnabled(config.trivialDataFetcherEnabled)
+ .setAddOperationNameToSpanName(config.addOperationNameToSpanName)
+ .build();
+ }
public static Instrumentation addInstrumentation(Instrumentation instrumentation) {
Instrumentation ourInstrumentation = TELEMETRY.newInstrumentation();
return InstrumentationUtil.addInstrumentation(instrumentation, ourInstrumentation);
}
+
+ // instrumentation/development:
+ // java:
+ // graphql:
+ // capture_query: true
+ // query_sanitizer:
+ // enabled: true
+ // data_fetcher:
+ // enabled: false
+ // trivial_data_fetcher:
+ // enabled: false
+ // add_operation_name_to_span_name:
+ // enabled: false
+ private static final class Configuration {
+
+ private final boolean captureQuery;
+ private final boolean sanitizeQuery;
+ private final boolean dataFetcherEnabled;
+ private final boolean trivialDataFetcherEnabled;
+ private final boolean addOperationNameToSpanName;
+
+ Configuration(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 graphqlConfig = javaConfig.getStructured("graphql", empty());
+
+ this.captureQuery = graphqlConfig.getBoolean("capture_query", true);
+ this.sanitizeQuery =
+ graphqlConfig.getStructured("query_sanitizer", empty()).getBoolean("enabled", true);
+ this.dataFetcherEnabled =
+ graphqlConfig.getStructured("data_fetcher", empty()).getBoolean("enabled", false);
+ this.trivialDataFetcherEnabled =
+ graphqlConfig.getStructured("trivial_data_fetcher", empty()).getBoolean("enabled", false);
+ this.addOperationNameToSpanName =
+ graphqlConfig
+ .getStructured("add_operation_name_to_span_name", empty())
+ .getBoolean("enabled", false);
+ }
+ }
+
+ private GraphqlSingletons() {}
}
diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodConfiguration.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodConfiguration.java
new file mode 100644
index 000000000000..4565ca08bbe0
--- /dev/null
+++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodConfiguration.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+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;
+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;
+import java.util.stream.Stream;
+
+public class MethodConfiguration {
+
+ private static final Logger logger = Logger.getLogger(MethodConfiguration.class.getName());
+
+ private final List typeInstrumentations;
+
+ 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(MethodConfiguration::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(
+ DeclarativeConfigProperties config) {
+ String clazz = config.getString("class");
+ if (isNullOrEmpty(clazz)) {
+ logger.log(Level.WARNING, "Invalid methods configuration - class name missing: {0}", config);
+ return Stream.empty();
+ }
+
+ Map> methodNames = new EnumMap<>(SpanKind.class);
+ for (DeclarativeConfigProperties method : config.getStructuredList("methods", emptyList())) {
+ String methodName = method.getString("name");
+ if (isNullOrEmpty(methodName)) {
+ logger.log(
+ Level.WARNING, "Invalid methods configuration - method name missing: {0}", method);
+ continue;
+ }
+ String spanKind = method.getString("span_kind", "INTERNAL");
+ try {
+ methodNames
+ .computeIfAbsent(
+ SpanKind.valueOf(spanKind.toUpperCase(Locale.ROOT)), unused -> new ArrayList<>())
+ .add(methodName);
+ } catch (IllegalArgumentException e) {
+ logger.log(
+ Level.WARNING,
+ "Invalid methods configuration - unknown span_kind: {0} for method: {1}",
+ new Object[] {spanKind, methodName});
+ }
+ }
+
+ if (methodNames.isEmpty()) {
+ logger.log(Level.WARNING, "Invalid methods configuration - no methods defined: {0}", config);
+ return Stream.empty();
+ }
+
+ return Stream.of(new MethodInstrumentation(clazz, methodNames));
+ }
+
+ 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/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..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
@@ -10,24 +10,17 @@
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.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 +29,8 @@ public MethodInstrumentationModule() {
}
private static List createInstrumentations() {
- InstrumentationConfig config = AgentInstrumentationConfig.get();
- List list =
- config.isDeclarative()
- ? MethodsConfig.parseDeclarativeConfig(config.getDeclarativeConfig("methods"))
- : parseConfigProperties();
+ 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()) {
@@ -50,20 +40,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
deleted file mode 100644
index 692ede856414..000000000000
--- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodsConfig.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.methods;
-
-import static java.util.Collections.emptyList;
-
-import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
-import io.opentelemetry.api.trace.SpanKind;
-import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
-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.logging.Level;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-public class MethodsConfig {
-
- private static final Logger logger = Logger.getLogger(MethodsConfig.class.getName());
-
- private MethodsConfig() {}
-
- static List parseDeclarativeConfig(DeclarativeConfigProperties methods) {
- return methods.getStructuredList("include", emptyList()).stream()
- .flatMap(MethodsConfig::parseMethodInstrumentation)
- .collect(Collectors.toList());
- }
-
- private static Stream parseMethodInstrumentation(
- DeclarativeConfigProperties config) {
- String clazz = config.getString("class");
- if (isNullOrEmpty(clazz)) {
- logger.log(Level.WARNING, "Invalid methods configuration - class name missing: {0}", config);
- return Stream.empty();
- }
-
- Map> methodNames = new EnumMap<>(SpanKind.class);
- for (DeclarativeConfigProperties method : config.getStructuredList("methods", emptyList())) {
- String methodName = method.getString("name");
- if (isNullOrEmpty(methodName)) {
- logger.log(
- Level.WARNING, "Invalid methods configuration - method name missing: {0}", method);
- continue;
- }
- String spanKind = method.getString("span_kind", "INTERNAL");
- try {
- methodNames
- .computeIfAbsent(
- SpanKind.valueOf(spanKind.toUpperCase(Locale.ROOT)), unused -> new ArrayList<>())
- .add(methodName);
- } catch (IllegalArgumentException e) {
- logger.log(
- Level.WARNING,
- "Invalid methods configuration - unknown span_kind: {0} for method: {1}",
- new Object[] {spanKind, methodName});
- }
- }
-
- if (methodNames.isEmpty()) {
- logger.log(Level.WARNING, "Invalid methods configuration - no methods defined: {0}", config);
- return Stream.empty();
- }
-
- return Stream.of(new MethodInstrumentation(clazz, methodNames));
- }
-
- private static boolean isNullOrEmpty(String s) {
- return s == null || s.isEmpty();
- }
-}
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 ff6cb22411d1..9e9789145f14 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,15 +7,18 @@
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty;
+import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.incubator.ExtendedOpenTelemetry;
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;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.SdkAutoconfigureAccess;
+import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.common.CompletableResultCode;
@@ -34,26 +37,32 @@ 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();
OpenTelemetrySdk sdk = autoConfiguredSdk.getOpenTelemetrySdk();
+ ConfigProperties configProperties = AutoConfigureUtil.getConfig(autoConfiguredSdk);
+ ConfigProvider configProvider;
+ if (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 {
+ // Provide a fake ConfigProperties until we have migrated all runtime configuration
+ // access to use declarative configuration API
+ configProvider = ((ExtendedOpenTelemetry) sdk).getConfigProvider();
+ configProperties = getDeclarativeConfigBridgedProperties(earlyConfig, configProvider);
+ }
setForceFlush(sdk);
+ GlobalOpenTelemetry.set(sdk);
- if (sdk instanceof ExtendedOpenTelemetry) {
- ConfigProvider configProvider = ((ExtendedOpenTelemetry) sdk).getConfigProvider();
- // 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