From 701e1f3127c537d2213753dd419a5a5bf0a6a123 Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:25:36 +0200 Subject: [PATCH 01/38] update opentelemetry-api to 1.47.0 --- dd-java-agent/agent-otel/otel-shim/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/agent-otel/otel-shim/build.gradle b/dd-java-agent/agent-otel/otel-shim/build.gradle index d622712f484..428f19de65d 100644 --- a/dd-java-agent/agent-otel/otel-shim/build.gradle +++ b/dd-java-agent/agent-otel/otel-shim/build.gradle @@ -5,7 +5,7 @@ minimumBranchCoverage = 0.0 dependencies { // minimum OpenTelemetry API version this shim is compatible with - compileOnly group: 'io.opentelemetry', name: 'opentelemetry-api', version: '1.4.0' + compileOnly group: 'io.opentelemetry', name: 'opentelemetry-api', version: '1.47.0' implementation project(':internal-api') } From aaeee116593903d88a69e052c105552be9f3088a Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:24:42 +0100 Subject: [PATCH 02/38] add otel metrics configuration --- .../datadog/trace/api/ConfigDefaults.java | 11 + .../datadog/trace/api/config/OtelConfig.java | 47 ++++ .../main/java/datadog/trace/api/Config.java | 217 +++++++++++++++- .../datadog/trace/api/ConfigTest.groovy | 245 +++++++++++++++++- .../config/provider/ConfigProvider.java | 21 +- .../datadog/trace/util/ConfigStrings.java | 4 +- 6 files changed, 540 insertions(+), 5 deletions(-) create mode 100644 dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index b42612f89bd..c5447df7da8 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -5,6 +5,7 @@ import static datadog.trace.api.TracePropagationStyle.TRACECONTEXT; import static java.util.Arrays.asList; +import datadog.trace.api.config.OtelConfig; import java.util.Arrays; import java.util.BitSet; import java.util.HashSet; @@ -100,6 +101,16 @@ public final class ConfigDefaults { static final boolean DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_ENABLED = false; static final int DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_LIMIT = 10; + static final boolean DEFAULT_METRICS_OTEL_ENABLED = false; + static final OtelConfig.Exporter DEFAULT_OTEL_METRICS_EXPORTER = OtelConfig.Exporter.OTLP; + // WARNING: This defies the OpenTelemetry specification’s default value of 60000 (60s) + static final int DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; + // WARNING: This defies the OpenTelemetry specification’s default value of 30000 (30s) + static final int DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT = 7500; + static final OtelConfig.Protocol DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = + OtelConfig.Protocol.GRPC; + static final int DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = 10000; + static final int DEFAULT_DOGSTATSD_START_DELAY = 15; // seconds static final boolean DEFAULT_HEALTH_METRICS_ENABLED = true; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java new file mode 100644 index 00000000000..5adb0c95bdd --- /dev/null +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java @@ -0,0 +1,47 @@ +package datadog.trace.api.config; + +public final class OtelConfig { + + public static final String METRICS_OTEL_ENABLED = "metrics.otel.enabled"; + public static final String OTEL_RESOURCE_ATTRIBUTES = "otel.resource.attributes"; + public static final String OTEL_METRICS_EXPORTER = "otel.metrics.exporter"; + public static final String OTEL_METRIC_EXPORT_INTERVAL = "otel.metric.export.interval"; + public static final String OTEL_METRIC_EXPORT_TIMEOUT = "otel.metric.export.timeout"; + public static final String OTEL_EXPORTER_OTLP_ENDPOINT = "otel.exporter.otlp.endpoint"; + public static final String OTEL_EXPORTER_OTLP_HEADERS = "otel.exporter.otlp.headers"; + public static final String OTEL_EXPORTER_OTLP_PROTOCOL = "otel.exporter.otlp.protocol"; + public static final String OTEL_EXPORTER_OTLP_TIMEOUT = "otel.exporter.otlp.timeout"; + public static final String OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = + "otel.exporter.otlp.metrics.endpoint"; + public static final String OTEL_EXPORTER_OTLP_METRICS_HEADERS = + "otel.exporter.otlp.metrics.headers"; + public static final String OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = + "otel.exporter.otlp.metrics.protocol"; + public static final String OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = + "otel.exporter.otlp.metrics.timeout"; + public static final String OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = + "otel.exporter.otlp.metrics.temporality.preference"; + + public static final String OTEL_METRIC_ENDPOINT_SUFFIX = "v1/metrics"; + public static final String OTEL_METRIC_ENDPOINT_HTTP_PORT = "4318"; + public static final String OTEL_METRIC_ENDPOINT_GRPC_PORT = "4317"; + + public enum Temporality { + CUMULATIVE, + DELTA, + LOWMEMORY; + } + + public enum Exporter { + OTLP, + NONE; + } + + public enum Protocol { + GRPC, + HTTP_PROTOBUF, + HTTP_JSON; + } + + private OtelConfig() {} +} diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index ef0a02114da..d345a9effa8 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -111,6 +111,12 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_LIMIT; import static datadog.trace.api.ConfigDefaults.DEFAULT_LLM_OBS_AGENTLESS_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_LOGS_INJECTION_ENABLED; +import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_ENABLED; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRICS_EXPORTER; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_EXPORT_INTERVAL; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT; import static datadog.trace.api.ConfigDefaults.DEFAULT_PARTIAL_FLUSH_MIN_SPANS; import static datadog.trace.api.ConfigDefaults.DEFAULT_PERF_METRICS_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_PRIORITY_SAMPLING_ENABLED; @@ -433,6 +439,23 @@ import static datadog.trace.api.config.JmxFetchConfig.JMX_TAGS; import static datadog.trace.api.config.LlmObsConfig.LLMOBS_AGENTLESS_ENABLED; import static datadog.trace.api.config.LlmObsConfig.LLMOBS_ML_APP; +import static datadog.trace.api.config.OtelConfig.METRICS_OTEL_ENABLED; +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_ENDPOINT; +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_HEADERS; +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT; +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS; +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE; +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_PROTOCOL; +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_TIMEOUT; +import static datadog.trace.api.config.OtelConfig.OTEL_METRICS_EXPORTER; +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_ENDPOINT_GRPC_PORT; +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_ENDPOINT_HTTP_PORT; +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_ENDPOINT_SUFFIX; +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_INTERVAL; +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_TIMEOUT; +import static datadog.trace.api.config.OtelConfig.OTEL_RESOURCE_ATTRIBUTES; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_API_KEY_FILE_OLD; @@ -660,6 +683,7 @@ import datadog.environment.SystemProperties; import datadog.trace.api.civisibility.CiVisibilityWellKnownTags; import datadog.trace.api.config.GeneralConfig; +import datadog.trace.api.config.OtelConfig; import datadog.trace.api.config.ProfilingConfig; import datadog.trace.api.config.TracerConfig; import datadog.trace.api.iast.IastContext; @@ -883,6 +907,17 @@ public static String getHostName() { private final boolean jmxFetchMultipleRuntimeServicesEnabled; private final int jmxFetchMultipleRuntimeServicesLimit; + private final boolean metricsOtelEnabled; + private final Map otelResourceAttributes; + private final OtelConfig.Exporter otelMetricsExporter; + private final Integer otelMetricExportInterval; + private final Integer otelMetricExportTimeout; + private final String otelExporterOtlpMetricsEndpoint; + private final Map otelExporterOtlpMetricsHeaders; + private final OtelConfig.Protocol otelExporterOtlpMetricsProtocol; + private final Integer otelExporterOtlpMetricsTimeout; + private final OtelConfig.Temporality otelExporterOtlpMetricsTemporalityPreference; + // These values are default-ed to those of jmx fetch values as needed private final boolean healthMetricsEnabled; private final String healthMetricsStatsdHost; @@ -1818,7 +1853,103 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins statsDClientSocketBuffer = configProvider.getInteger(STATSD_CLIENT_SOCKET_BUFFER); statsDClientSocketTimeout = configProvider.getInteger(STATSD_CLIENT_SOCKET_TIMEOUT); - runtimeMetricsEnabled = configProvider.getBoolean(RUNTIME_METRICS_ENABLED, true); + metricsOtelEnabled = + configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED); + otelResourceAttributes = + getHashMap(configProvider.getList(OTEL_RESOURCE_ATTRIBUTES), OTEL_RESOURCE_ATTRIBUTES, "="); + otelMetricsExporter = + configProvider.getEnum( + OTEL_METRICS_EXPORTER, OtelConfig.Exporter.class, DEFAULT_OTEL_METRICS_EXPORTER, false); + + int tmpOtelMetricExportTimeout = + configProvider.getInteger(OTEL_METRIC_EXPORT_TIMEOUT, DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT); + otelMetricExportTimeout = + (tmpOtelMetricExportTimeout < 0) + ? DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT + : tmpOtelMetricExportTimeout; + + int tmpOtelMetricExportInterval = + configProvider.getInteger(OTEL_METRIC_EXPORT_INTERVAL, DEFAULT_OTEL_METRIC_EXPORT_INTERVAL); + otelMetricExportInterval = + (tmpOtelMetricExportInterval < 0) + ? DEFAULT_OTEL_METRIC_EXPORT_INTERVAL + : tmpOtelMetricExportInterval; + + List tmpOtelExporterOtlpMetricsHeaders = + configProvider.getList(OTEL_EXPORTER_OTLP_METRICS_HEADERS); + otelExporterOtlpMetricsHeaders = + tmpOtelExporterOtlpMetricsHeaders.isEmpty() + ? getHashMap( + configProvider.getList(OTEL_EXPORTER_OTLP_HEADERS), OTEL_EXPORTER_OTLP_HEADERS, "=") + : getHashMap( + tmpOtelExporterOtlpMetricsHeaders, OTEL_EXPORTER_OTLP_METRICS_HEADERS, "="); + + OtelConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = + configProvider.getEnum( + OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OtelConfig.Protocol.class, null, false, "/", "_"); + if (tmpOtelExporterOtlpMetricsProtocol == null) { + tmpOtelExporterOtlpMetricsProtocol = + configProvider.getEnum( + OTEL_EXPORTER_OTLP_PROTOCOL, + OtelConfig.Protocol.class, + DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, + false, + "/", + "_"); + } + otelExporterOtlpMetricsProtocol = tmpOtelExporterOtlpMetricsProtocol; + // TO DO + // Add some error log and switch the protocol to the default value if we don't support the + // selected protocol + + String tmpOtelExporterOtlpMetricsEndpoint = + configProvider.getString(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT); + if (tmpOtelExporterOtlpMetricsEndpoint == null) { + boolean isHttp = !otelExporterOtlpMetricsProtocol.equals(OtelConfig.Protocol.GRPC); + String tmpOtelExporterOtlpEndpoint = configProvider.getString(OTEL_EXPORTER_OTLP_ENDPOINT); + if (null == tmpOtelExporterOtlpEndpoint) { + String endpointHost = agentHost.isEmpty() ? DEFAULT_AGENT_HOST : agentHost; + tmpOtelExporterOtlpMetricsEndpoint = + isHttp + ? "http://" + + endpointHost + + ":" + + OTEL_METRIC_ENDPOINT_HTTP_PORT + + "/" + + OTEL_METRIC_ENDPOINT_SUFFIX + : "http://" + endpointHost + ":" + OTEL_METRIC_ENDPOINT_GRPC_PORT; + } else { + tmpOtelExporterOtlpMetricsEndpoint = + isHttp + ? tmpOtelExporterOtlpEndpoint.concat(OTEL_METRIC_ENDPOINT_SUFFIX) + : tmpOtelExporterOtlpEndpoint; + } + } + otelExporterOtlpMetricsEndpoint = tmpOtelExporterOtlpMetricsEndpoint; + + Integer tmpOtelExporterOtlpMetricsTimeout = + configProvider.getInteger(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT); + if (null == tmpOtelExporterOtlpMetricsTimeout) { + tmpOtelExporterOtlpMetricsTimeout = + configProvider.getInteger( + OTEL_EXPORTER_OTLP_TIMEOUT, DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT); + } + otelExporterOtlpMetricsTimeout = + tmpOtelExporterOtlpMetricsTimeout < 0 + ? DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT + : tmpOtelExporterOtlpMetricsTimeout; + + otelExporterOtlpMetricsTemporalityPreference = + configProvider.getEnum( + OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, + OtelConfig.Temporality.class, + OtelConfig.Temporality.DELTA, + false); + + // Runtime metrics are disabled if Otel metrics are enabled and the metrics exporter is none + runtimeMetricsEnabled = + (!metricsOtelEnabled || !otelMetricsExporter.equals(OtelConfig.Exporter.NONE)) + && configProvider.getBoolean(RUNTIME_METRICS_ENABLED, true); jmxFetchEnabled = runtimeMetricsEnabled @@ -4936,6 +5067,46 @@ public boolean isJmxFetchIntegrationEnabled( return configProvider.isEnabled(integrationNames, "jmxfetch.", ".enabled", defaultEnabled); } + public boolean isMetricsOtelEnabled() { + return metricsOtelEnabled; + } + + public Map getOtelResourceAttributes() { + return otelResourceAttributes; + } + + public OtelConfig.Exporter getOtelMetricsExporter() { + return otelMetricsExporter; + } + + public Integer getOtelMetricExportInterval() { + return otelMetricExportInterval; + } + + public Integer getOtelMetricExportTimeout() { + return otelMetricExportTimeout; + } + + public String getOtelExporterOtlpMetricsEndpoint() { + return otelExporterOtlpMetricsEndpoint; + } + + public Map getOtelExporterOtlpMetricsHeaders() { + return otelExporterOtlpMetricsHeaders; + } + + public OtelConfig.Protocol getOtelExporterOtlpMetricsProtocol() { + return otelExporterOtlpMetricsProtocol; + } + + public Integer getOtelExporterOtlpMetricsTimeout() { + return otelExporterOtlpMetricsTimeout; + } + + public OtelConfig.Temporality getOtelExporterOtlpMetricsTemporalityPreference() { + return otelExporterOtlpMetricsTemporalityPreference; + } + public boolean isRuleEnabled(final String name) { return isRuleEnabled(name, true); } @@ -5322,6 +5493,30 @@ private static Set convertStringSetToSet( return Collections.unmodifiableSet(result); } + private static Map getHashMap( + List inputAsList, String key, String delimiter) { + Map finalValue = new HashMap<>(); + if (!inputAsList.isEmpty()) { + boolean error = false; + for (String keyvalue : inputAsList) { + int indexOfSplit = keyvalue.indexOf(delimiter); + if (indexOfSplit < 0) { + error = true; + continue; + } + finalValue.put(keyvalue.substring(0, indexOfSplit), keyvalue.substring(indexOfSplit + 1)); + } + if (error) { + log.debug( + "Parsing error occurs for {}, value provided: {}; value taken into account: {}", + key, + inputAsList, + finalValue); + } + } + return finalValue; + } + /** Returns the detected hostname. First tries locally, then using DNS */ static String initHostName() { String possibleHostname; @@ -5916,6 +6111,26 @@ public String toString() { + aiGuardEnabled + ", aiGuardEndpoint=" + aiGuardEndpoint + + ", metricsOtelEnabled=" + + metricsOtelEnabled + + ", otelResourceAttributes=" + + otelResourceAttributes + + ", otelMetricsExporter=" + + otelMetricsExporter + + ", otelMetricExportInterval=" + + otelMetricExportInterval + + ", otelMetricExportTimeout=" + + otelMetricExportTimeout + + ", otelExporterOtlpMetricsEndpoint=" + + otelExporterOtlpMetricsEndpoint + + ", otelExporterOtlpMetricsHeaders=" + + otelExporterOtlpMetricsHeaders + + ", otelExporterOtlpMetricsProtocol=" + + otelExporterOtlpMetricsProtocol + + ", otelExporterOtlpMetricsTimeout=" + + otelExporterOtlpMetricsTimeout + + ", otelExporterOtlpMetricsTemporalityPreference=" + + otelExporterOtlpMetricsTemporalityPreference + '}'; } } diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 2d5b1518f99..646514a9592 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -58,6 +58,7 @@ import static datadog.trace.api.config.GeneralConfig.SITE import static datadog.trace.api.config.GeneralConfig.TAGS import static datadog.trace.api.config.GeneralConfig.TRACER_METRICS_IGNORED_RESOURCES import static datadog.trace.api.config.GeneralConfig.VERSION +import static datadog.trace.api.config.GeneralConfig.RUNTIME_METRICS_ENABLED import static datadog.trace.api.config.GeneralConfig.SSI_INJECTION_ENABLED import static datadog.trace.api.config.GeneralConfig.SSI_INJECTION_FORCE import static datadog.trace.api.config.GeneralConfig.INSTRUMENTATION_SOURCE @@ -137,6 +138,26 @@ import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_OPERATION_RUL import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_SERVICE_RULES import static datadog.trace.api.config.TracerConfig.TRACE_X_DATADOG_TAGS_MAX_LENGTH import static datadog.trace.api.config.TracerConfig.WRITER_TYPE +import static datadog.trace.api.config.OtelConfig.Protocol.GRPC +import static datadog.trace.api.config.OtelConfig.Protocol.HTTP_PROTOBUF +import static datadog.trace.api.config.OtelConfig.Protocol.HTTP_JSON +import static datadog.trace.api.config.OtelConfig.Exporter.OTLP +import static datadog.trace.api.config.OtelConfig.Temporality.CUMULATIVE +import static datadog.trace.api.config.OtelConfig.Temporality.DELTA +import static datadog.trace.api.config.OtelConfig.METRICS_OTEL_ENABLED +import static datadog.trace.api.config.OtelConfig.OTEL_RESOURCE_ATTRIBUTES +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_ENDPOINT +import static datadog.trace.api.config.OtelConfig.OTEL_METRICS_EXPORTER +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_INTERVAL +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_TIMEOUT +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_PROTOCOL +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_TIMEOUT +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_HEADERS +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT +import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE class ConfigTest extends DDSpecification { private static final String PREFIX = "dd." @@ -173,6 +194,21 @@ class ConfigTest extends DDSpecification { private static final DD_LLMOBS_ML_APP_ENV = "DD_LLMOBS_ML_APP" private static final DD_LLMOBS_AGENTLESS_ENABLED_ENV = "DD_LLMOBS_AGENTLESS_ENABLED" + + + private static final DD_METRICS_OTEL_ENABLED_ENV = "DD_METRICS_OTEL_ENABLED" + private static final OTEL_RESOURCE_ATTRIBUTES_ENV = "OTEL_RESOURCE_ATTRIBUTES" + private static final OTEL_METRICS_EXPORTER_ENV = "OTEL_METRICS_EXPORTER" + private static final OTEL_METRIC_EXPORT_TIMEOUT_ENV = "OTEL_METRIC_EXPORT_TIMEOUT" + private static final OTEL_METRIC_EXPORT_INTERVAL_ENV = "OTEL_METRIC_EXPORT_INTERVAL" + private static final OTEL_EXPORTER_OTLP_METRICS_ENDPOINT_ENV = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" + private static final OTEL_EXPORTER_OTLP_METRICS_HEADERS_ENV = "OTEL_EXPORTER_OTLP_METRICS_HEADERS" + private static final OTEL_EXPORTER_OTLP_METRICS_PROTOCOL_ENV = "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL" + private static final OTEL_EXPORTER_OTLP_METRICS_TIMEOUT_ENV = "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT" + private static final OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE_ENV = "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE" + + + def setup() { FixedCapturedEnvironment.useFixedEnv([:]) } @@ -270,6 +306,17 @@ class ConfigTest extends DDSpecification { prop.setProperty(TRACE_X_DATADOG_TAGS_MAX_LENGTH, "128") prop.setProperty(JDK_SOCKET_ENABLED, "false") + prop.setProperty(METRICS_OTEL_ENABLED, "True") + prop.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app,service.version=1.0.0,deployment.environment=production") + prop.setProperty(OTEL_METRICS_EXPORTER, "otlp") + prop.setProperty(OTEL_METRIC_EXPORT_INTERVAL, "11000") + prop.setProperty(OTEL_METRIC_EXPORT_TIMEOUT, "9000") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "api-key=key,other-config-value=value") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, "http/protobuf") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT, "5000") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, "cumulative") + when: Config config = Config.get(prop) @@ -363,11 +410,159 @@ class ConfigTest extends DDSpecification { config.dynamicInstrumentationInstrumentTheWorld == "method" config.dynamicInstrumentationExcludeFiles == "exclude file" config.debuggerExceptionEnabled == true + config.xDatadogTagsMaxLength == 128 config.jdkSocketEnabled == false - config.xDatadogTagsMaxLength == 128 + config.metricsOtelEnabled + config.otelResourceAttributes["service.name"] == "my=app" + config.otelResourceAttributes["service.version"] == "1.0.0" + config.otelResourceAttributes["deployment.environment"] == "production" + config.otelMetricsExporter == OTLP + config.otelMetricExportInterval == 11000 + config.otelMetricExportTimeout == 9000 + config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" + config.otelExporterOtlpMetricsHeaders["api-key"] == "key" + config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" + config.otelExporterOtlpMetricsProtocol == HTTP_PROTOBUF + config.otelExporterOtlpMetricsTimeout == 5000 + config.otelExporterOtlpMetricsTemporalityPreference == CUMULATIVE + + } + + def "otel metrics: default values when configured incorrectly"() { + setup: + def prop = new Properties() + + prop.setProperty(METRICS_OTEL_ENABLED, "youhou") + prop.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service") + prop.setProperty(OTEL_METRICS_EXPORTER, "invalid") + prop.setProperty(OTEL_METRIC_EXPORT_INTERVAL, "-1") + prop.setProperty(OTEL_METRIC_EXPORT_TIMEOUT, "invalid") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, "invalid") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "11") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, "invalid") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT, "-34") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, "invalid") + + when: + Config config = Config.get(prop) + + then: + !config.metricsOtelEnabled + config.otelResourceAttributes == [:] + config.otelMetricsExporter == OTLP + config.otelMetricExportInterval == 10000 + config.otelMetricExportTimeout == 7500 + config.otelExporterOtlpMetricsEndpoint == "invalid" + config.otelExporterOtlpMetricsHeaders == [:] + config.otelExporterOtlpMetricsProtocol == GRPC + config.otelExporterOtlpMetricsTimeout == 10000 + config.otelExporterOtlpMetricsTemporalityPreference == DELTA + } + + + def "otel metrics: default values when not set"() { + setup: + def prop = new Properties() + + when: + Config config = Config.get(prop) + + then: + !config.metricsOtelEnabled + config.otelResourceAttributes == [:] + config.otelMetricsExporter == OTLP + config.otelMetricExportInterval == 10000 + config.otelMetricExportTimeout == 7500 + config.otelExporterOtlpMetricsEndpoint == "http://localhost:4317" + config.otelExporterOtlpMetricsHeaders == [:] + config.otelExporterOtlpMetricsProtocol == GRPC + config.otelExporterOtlpMetricsTimeout == 10000 + config.otelExporterOtlpMetricsTemporalityPreference == DELTA + } + + + def "otel metrics: check syntax for attributes and headers"() { + setup: + def prop = new Properties() + prop.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app=56,version=1.0.0,deployment:environment") + prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "api,key=key") + + when: + Config config = Config.get(prop) + + then: + config.otelResourceAttributes.size() == 2 + config.otelResourceAttributes["service.name"] == "my=app=56" + config.otelResourceAttributes["version"] == "1.0.0" + config.otelExporterOtlpMetricsHeaders.size() == 1 + config.otelExporterOtlpMetricsHeaders["key"] == "key" } + + def "otel metrics enabled, exporter none => runtime metrics should be disabled "() { + setup: + def prop = new Properties() + prop.setProperty(METRICS_OTEL_ENABLED, "true") + prop.setProperty(OTEL_METRICS_EXPORTER, "none") + prop.setProperty(PREFIX + RUNTIME_METRICS_ENABLED, "true") + + when: + Config config = Config.get(prop) + + then: + !config.runtimeMetricsEnabled + } + + def "otel metrics: fallback keys"() { + setup: + def prop = new Properties() + prop.setProperty(OTEL_EXPORTER_OTLP_PROTOCOL, "http/json") + prop.setProperty(OTEL_EXPORTER_OTLP_ENDPOINT,"http://localhost:4319/") + prop.setProperty(OTEL_EXPORTER_OTLP_HEADERS,"api-key=key,other-config-value=value") + prop.setProperty(OTEL_EXPORTER_OTLP_TIMEOUT,"1000") + + when: + Config config = Config.get(prop) + + then: + config.otelExporterOtlpMetricsProtocol == HTTP_JSON + config.otelExporterOtlpMetricsEndpoint == "http://localhost:4319/v1/metrics" + config.otelExporterOtlpMetricsHeaders.size() == 2 + config.otelExporterOtlpMetricsHeaders["api-key"] == "key" + config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" + config.otelExporterOtlpMetricsTimeout == 1000 + } + def "otel metrics: fallback key endpoint"() { + setup: + def prop = new Properties() + prop.setProperty(OTEL_EXPORTER_OTLP_PROTOCOL, "http/json") + prop.setProperty(TRACE_AGENT_URL,"http://192.168.0.3:8126/") + + when: + Config config = Config.get(prop) + + then: + config.agentHost == "192.168.0.3" + config.otelExporterOtlpMetricsProtocol == HTTP_JSON + config.otelExporterOtlpMetricsEndpoint == "http://192.168.0.3:4318/v1/metrics" + } + + def "otel metrics: fallback key endpoint 2"() { + setup: + def prop = new Properties() + prop.setProperty(TRACE_AGENT_URL,"'/tmp/ddagent/trace.sock'") + + when: + Config config = Config.get(prop) + + then: + config.agentHost == "localhost" + config.otelExporterOtlpMetricsProtocol == GRPC + config.otelExporterOtlpMetricsEndpoint == "http://localhost:4317" + } + + def "specify overrides via system properties"() { setup: System.setProperty(PREFIX + API_KEY, "new api key") @@ -459,6 +654,17 @@ class ConfigTest extends DDSpecification { System.setProperty(PREFIX + DYNAMIC_INSTRUMENTATION_EXCLUDE_FILES, "exclude file") System.setProperty(PREFIX + TRACE_X_DATADOG_TAGS_MAX_LENGTH, "128") + System.setProperty(PREFIX + METRICS_OTEL_ENABLED, "True") + System.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app,service.version=1.0.0,deployment.environment=production") + System.setProperty(OTEL_METRICS_EXPORTER, "otlp") + System.setProperty(OTEL_METRIC_EXPORT_INTERVAL, "11000") + System.setProperty(OTEL_METRIC_EXPORT_TIMEOUT, "9000") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "api-key=key,other-config-value=value") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, "http/protobuf") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT, "5000") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, "cumulative") + when: Config config = new Config() @@ -551,6 +757,20 @@ class ConfigTest extends DDSpecification { config.dynamicInstrumentationExcludeFiles == "exclude file" config.xDatadogTagsMaxLength == 128 + + config.metricsOtelEnabled + config.otelResourceAttributes["service.name"] == "my=app" + config.otelResourceAttributes["service.version"] == "1.0.0" + config.otelResourceAttributes["deployment.environment"] == "production" + config.otelMetricsExporter == OTLP + config.otelMetricExportInterval == 11000 + config.otelMetricExportTimeout == 9000 + config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" + config.otelExporterOtlpMetricsHeaders["api-key"] == "key" + config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" + config.otelExporterOtlpMetricsProtocol == HTTP_PROTOBUF + config.otelExporterOtlpMetricsTimeout == 5000 + config.otelExporterOtlpMetricsTemporalityPreference == CUMULATIVE } def "specify overrides via env vars"() { @@ -569,6 +789,16 @@ class ConfigTest extends DDSpecification { environmentVariables.set(DD_TRACE_LONG_RUNNING_ENABLED, "true") environmentVariables.set(DD_TRACE_LONG_RUNNING_FLUSH_INTERVAL, "81") environmentVariables.set(DD_TRACE_HEADER_TAGS, "*") + environmentVariables.set(DD_METRICS_OTEL_ENABLED_ENV, "True") + environmentVariables.set(OTEL_RESOURCE_ATTRIBUTES_ENV, "service.name=my=app,service.version=1.0.0,deployment.environment=production") + environmentVariables.set(OTEL_METRICS_EXPORTER_ENV, "otlp") + environmentVariables.set(OTEL_METRIC_EXPORT_INTERVAL_ENV, "11000") + environmentVariables.set(OTEL_METRIC_EXPORT_TIMEOUT_ENV, "9000") + environmentVariables.set(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT_ENV, "http://localhost:4333/v1/metrics") + environmentVariables.set(OTEL_EXPORTER_OTLP_METRICS_HEADERS_ENV, "api-key=key,other-config-value=value") + environmentVariables.set(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL_ENV, "http/protobuf") + environmentVariables.set(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT_ENV, "5000") + environmentVariables.set(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE_ENV, "cumulative") when: def config = new Config() @@ -590,6 +820,19 @@ class ConfigTest extends DDSpecification { config.getLongRunningTraceFlushInterval() == 81 config.requestHeaderTags == ["*":"http.request.headers."] config.responseHeaderTags == ["*":"http.response.headers."] + config.metricsOtelEnabled + config.otelResourceAttributes["service.name"] == "my=app" + config.otelResourceAttributes["service.version"] == "1.0.0" + config.otelResourceAttributes["deployment.environment"] == "production" + config.otelMetricsExporter == OTLP + config.otelMetricExportInterval == 11000 + config.otelMetricExportTimeout == 9000 + config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" + config.otelExporterOtlpMetricsHeaders["api-key"] == "key" + config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" + config.otelExporterOtlpMetricsProtocol == HTTP_PROTOBUF + config.otelExporterOtlpMetricsTimeout == 5000 + config.otelExporterOtlpMetricsTemporalityPreference == CUMULATIVE } def "sys props override env vars"() { diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java index ade045011db..dfd2b78c9fd 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java @@ -101,6 +101,21 @@ private String getStringInternal(String key, String... aliases) { } public > T getEnum(String key, Class enumType, T defaultValue) { + return getEnum(key, enumType, defaultValue, true); + } + + public > T getEnum( + String key, Class enumType, T defaultValue, boolean isValueCaseSensitive) { + return getEnum(key, enumType, defaultValue, isValueCaseSensitive, "", ""); + } + + public > T getEnum( + String key, + Class enumType, + T defaultValue, + boolean isValueCaseSensitive, + String charToReplaceInRawValue, + String newCharInValue) { if (collectConfig) { String defaultValueString = defaultValue == null ? null : defaultValue.name(); reportDefault(key, defaultValueString); @@ -108,7 +123,11 @@ public > T getEnum(String key, Class enumType, T defaultVal String value = getStringInternal(key); if (null != value) { try { - return Enum.valueOf(enumType, value); + return Enum.valueOf( + enumType, + isValueCaseSensitive + ? value.replace(charToReplaceInRawValue, newCharInValue) + : value.toUpperCase().replace(charToReplaceInRawValue, newCharInValue)); } catch (Exception ignoreAndUseDefault) { log.debug("failed to parse {} for {}, defaulting to {}", value, key, defaultValue); } diff --git a/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java b/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java index 137280ad539..11c508ac80a 100644 --- a/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java +++ b/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java @@ -23,7 +23,7 @@ public static String toEnvVarLowerCase(String string) { */ @Nonnull public static String propertyNameToEnvironmentVariableName(final String setting) { - return "DD_" + toEnvVar(setting); + return setting.startsWith("otel.") ? toEnvVar(setting) : "DD_" + toEnvVar(setting); } /** @@ -47,7 +47,7 @@ public static String systemPropertyNameToEnvironmentVariableName(final String se */ @Nonnull public static String propertyNameToSystemPropertyName(final String setting) { - return "dd." + setting; + return setting.startsWith("otel.") ? setting : "dd." + setting; } @Nonnull From 97a145071dedb000acb9d68f7b2d52613d014192 Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 27 Oct 2025 12:36:38 +0100 Subject: [PATCH 03/38] solve P2 spotbugsMain --- internal-api/src/main/java/datadog/trace/api/Config.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 453394c0492..dba25233b07 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -1936,8 +1936,8 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins OTEL_EXPORTER_OTLP_TIMEOUT, DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT); } otelExporterOtlpMetricsTimeout = - tmpOtelExporterOtlpMetricsTimeout < 0 - ? DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT + (tmpOtelExporterOtlpMetricsTimeout < 0) + ? new Integer(DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT) : tmpOtelExporterOtlpMetricsTimeout; otelExporterOtlpMetricsTemporalityPreference = From 2e5d917956863412ac38297fa3d44d7ae1df63a6 Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:33:00 +0100 Subject: [PATCH 04/38] remove enum from jacocoTest coverage --- dd-trace-api/build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dd-trace-api/build.gradle.kts b/dd-trace-api/build.gradle.kts index f191c71be0e..490da71e4d7 100644 --- a/dd-trace-api/build.gradle.kts +++ b/dd-trace-api/build.gradle.kts @@ -63,6 +63,9 @@ val excludedClassesCoverage by extra( "datadog.trace.payloadtags.PayloadTagsData", "datadog.trace.payloadtags.PayloadTagsData.PathAndValue", "datadog.trace.api.llmobs.LLMObsTags", + "datadog.trace.api.config.OtelConfig.Protocol", + "datadog.trace.api.config.OtelConfig.Temporality", + "datadog.trace.api.config.OtelConfig.Exporter", ) ) From 0f27db43b2aff0b430916fe1e34f4ff9d397a4be Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:10:26 +0100 Subject: [PATCH 05/38] fix :jacocoTestCoverageVerification for :utils:config-utils --- .../trace/api/ConfigStringsTest.groovy | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 utils/config-utils/src/test/groovy/datadog/trace/api/ConfigStringsTest.groovy diff --git a/utils/config-utils/src/test/groovy/datadog/trace/api/ConfigStringsTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/api/ConfigStringsTest.groovy new file mode 100644 index 00000000000..6a52eabe1a0 --- /dev/null +++ b/utils/config-utils/src/test/groovy/datadog/trace/api/ConfigStringsTest.groovy @@ -0,0 +1,20 @@ +package datadog.trace.api + +import datadog.trace.test.util.DDSpecification +import datadog.trace.util.ConfigStrings + +class ConfigStringsTest extends DDSpecification { + + + def "test EnvironmentVariable from propertyName"() { + expect: + "DD_FOO_BAR_QUX" == ConfigStrings.propertyNameToEnvironmentVariableName("foo.bar-qux") + "OTEL_BAR_QUX" == ConfigStrings.propertyNameToEnvironmentVariableName("otel.bar-qux") + } + + def "test SystemPropertyName from propertyName"() { + expect: + "dd.foo.bar-qux" == ConfigStrings.propertyNameToSystemPropertyName("foo.bar-qux") + "otel.bar-qux" == ConfigStrings.propertyNameToSystemPropertyName("otel.bar-qux") + } +} From c0500b2430823e7c372edae85b2cb59e614bdf76 Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:14:50 +0100 Subject: [PATCH 06/38] add otel metrics configuration keys to Centralized Configuration --- metadata/supported-configurations.json | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index c67ba742a1c..957f1f22f8a 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -281,6 +281,7 @@ "DD_LOG_LEVEL": ["A"], "DD_MEASURE_METHODS": ["A"], "DD_MESSAGE_BROKER_SPLIT_BY_DESTINATION": ["A"], + "DD_METRICS_OTEL_ENABLED": ["A"], "DD_OBFUSCATION_QUERY_STRING_REGEXP": ["A"], "DD_OPTIMIZED_MAP_ENABLED": ["A"], "DD_PIPELINE_EXECUTION_ID": ["A"], @@ -1355,7 +1356,22 @@ "OTEL_SERVICE_NAME": ["A"], "OTEL_TRACES_EXPORTER": ["A"], "OTEL_TRACES_SAMPLER_ARG": ["A"], - "OTEL_TRACES_SAMPLER": ["A"] + "OTEL_TRACES_SAMPLER": ["A"], + "OTEL_TRACES_SAMPLER_ARG": ["A"], + "OTEL_TRACES_SAMPLER": ["A"], + "OTEL_RESOURCE_ATTRIBUTES": ["A"], + "OTEL_METRICS_EXPORTER": ["A"], + "OTEL_METRIC_EXPORT_INTERVAL": ["A"], + "OTEL_METRIC_EXPORT_TIMEOUT": ["A"], + "OTEL_EXPORTER_OTLP_ENDPOINT": ["A"], + "OTEL_EXPORTER_OTLP_HEADERS": ["A"], + "OTEL_EXPORTER_OTLP_PROTOCOL": ["A"], + "OTEL_EXPORTER_OTLP_TIMEOUT": ["A"], + "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": ["A"], + "OTEL_EXPORTER_OTLP_METRICS_HEADERS": ["A"], + "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL": ["A"], + "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT": ["A"], + "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE": ["A"] }, "aliases": { "DD_APPLICATION_KEY": ["DD_APP_KEY"], From b00f6c084a8d91a25ae869a93672f8514f5db54c Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 27 Oct 2025 17:15:37 +0100 Subject: [PATCH 07/38] initialized at build time OtelConfig and OtelConfig --- .../nativeimage/NativeImageGeneratorRunnerInstrumentation.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java index 00d9cfcf863..593ad9e4f42 100644 --- a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java +++ b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java @@ -84,6 +84,8 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[ + "datadog.trace.api.ConfigDefaults:build_time," + "datadog.trace.api.ConfigOrigin:build_time," + "datadog.trace.api.ConfigSetting:build_time," + + "datadog.trace.api.config.OtelConfig$Protocol:build_time," + + "datadog.trace.api.config.OtelConfig$Exporter:build_time," + "datadog.trace.api.EventTracker:build_time," + "datadog.trace.api.InstrumenterConfig:build_time," + "datadog.trace.api.Functions:build_time," From 998d75a0166a0ab9dcbd5679f26e8392a6560038 Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:28:56 +0100 Subject: [PATCH 08/38] easy improvements following feedback --- .../datadog/trace/api/ConfigDefaults.java | 4 +-- .../datadog/trace/api/config/OtelConfig.java | 6 ++-- .../main/java/datadog/trace/api/Config.java | 30 ++++++++----------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 92b5b81a22d..306369a770b 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -104,9 +104,9 @@ public final class ConfigDefaults { static final boolean DEFAULT_METRICS_OTEL_ENABLED = false; static final OtelConfig.Exporter DEFAULT_OTEL_METRICS_EXPORTER = OtelConfig.Exporter.OTLP; // WARNING: This defies the OpenTelemetry specification’s default value of 60000 (60s) - static final int DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; + static final Integer DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; // WARNING: This defies the OpenTelemetry specification’s default value of 30000 (30s) - static final int DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT = 7500; + static final Integer DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT = 7500; static final OtelConfig.Protocol DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = OtelConfig.Protocol.GRPC; static final int DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = 10000; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java index 5adb0c95bdd..8d24805dfd8 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java @@ -22,9 +22,9 @@ public final class OtelConfig { public static final String OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = "otel.exporter.otlp.metrics.temporality.preference"; - public static final String OTEL_METRIC_ENDPOINT_SUFFIX = "v1/metrics"; - public static final String OTEL_METRIC_ENDPOINT_HTTP_PORT = "4318"; - public static final String OTEL_METRIC_ENDPOINT_GRPC_PORT = "4317"; + public static final String OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX = "v1/metrics"; + public static final String OTEL_METRIC_DEFAULT_ENDPOINT_HTTP_PORT = "4318"; + public static final String OTEL_METRIC_DEFAULT_ENDPOINT_GRPC_PORT = "4317"; public enum Temporality { CUMULATIVE, diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index dba25233b07..e8c5185b9a5 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -449,9 +449,9 @@ import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_PROTOCOL; import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_TIMEOUT; import static datadog.trace.api.config.OtelConfig.OTEL_METRICS_EXPORTER; -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_ENDPOINT_GRPC_PORT; -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_ENDPOINT_HTTP_PORT; -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_ENDPOINT_SUFFIX; +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_DEFAULT_ENDPOINT_GRPC_PORT; +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_DEFAULT_ENDPOINT_HTTP_PORT; +import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX; import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_INTERVAL; import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_TIMEOUT; import static datadog.trace.api.config.OtelConfig.OTEL_RESOURCE_ATTRIBUTES; @@ -1862,17 +1862,15 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins configProvider.getEnum( OTEL_METRICS_EXPORTER, OtelConfig.Exporter.class, DEFAULT_OTEL_METRICS_EXPORTER, false); - int tmpOtelMetricExportTimeout = - configProvider.getInteger(OTEL_METRIC_EXPORT_TIMEOUT, DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT); + Integer tmpOtelMetricExportTimeout = configProvider.getInteger(OTEL_METRIC_EXPORT_TIMEOUT); otelMetricExportTimeout = - (tmpOtelMetricExportTimeout < 0) + (tmpOtelMetricExportTimeout == null || tmpOtelMetricExportTimeout < 0) ? DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT : tmpOtelMetricExportTimeout; - int tmpOtelMetricExportInterval = - configProvider.getInteger(OTEL_METRIC_EXPORT_INTERVAL, DEFAULT_OTEL_METRIC_EXPORT_INTERVAL); + Integer tmpOtelMetricExportInterval = configProvider.getInteger(OTEL_METRIC_EXPORT_INTERVAL); otelMetricExportInterval = - (tmpOtelMetricExportInterval < 0) + (tmpOtelMetricExportInterval == null || tmpOtelMetricExportInterval < 0) ? DEFAULT_OTEL_METRIC_EXPORT_INTERVAL : tmpOtelMetricExportInterval; @@ -1915,14 +1913,14 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins ? "http://" + endpointHost + ":" - + OTEL_METRIC_ENDPOINT_HTTP_PORT + + OTEL_METRIC_DEFAULT_ENDPOINT_HTTP_PORT + "/" - + OTEL_METRIC_ENDPOINT_SUFFIX - : "http://" + endpointHost + ":" + OTEL_METRIC_ENDPOINT_GRPC_PORT; + + OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX + : "http://" + endpointHost + ":" + OTEL_METRIC_DEFAULT_ENDPOINT_GRPC_PORT; } else { tmpOtelExporterOtlpMetricsEndpoint = isHttp - ? tmpOtelExporterOtlpEndpoint.concat(OTEL_METRIC_ENDPOINT_SUFFIX) + ? tmpOtelExporterOtlpEndpoint.concat(OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX) : tmpOtelExporterOtlpEndpoint; } } @@ -1931,12 +1929,10 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins Integer tmpOtelExporterOtlpMetricsTimeout = configProvider.getInteger(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT); if (null == tmpOtelExporterOtlpMetricsTimeout) { - tmpOtelExporterOtlpMetricsTimeout = - configProvider.getInteger( - OTEL_EXPORTER_OTLP_TIMEOUT, DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT); + tmpOtelExporterOtlpMetricsTimeout = configProvider.getInteger(OTEL_EXPORTER_OTLP_TIMEOUT); } otelExporterOtlpMetricsTimeout = - (tmpOtelExporterOtlpMetricsTimeout < 0) + (tmpOtelExporterOtlpMetricsTimeout == null || tmpOtelExporterOtlpMetricsTimeout < 0) ? new Integer(DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT) : tmpOtelExporterOtlpMetricsTimeout; From 10e9e680d146dee131a976070e76a2a8be8bfc47 Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:46:33 +0100 Subject: [PATCH 09/38] use previous existing function for Map --- .../main/java/datadog/trace/api/Config.java | 43 ++++--------------- .../datadog/trace/api/ConfigTest.groovy | 8 ++-- .../config/provider/ConfigProvider.java | 6 ++- 3 files changed, 17 insertions(+), 40 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index e8c5185b9a5..f63bcc1383e 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -1856,8 +1856,8 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins metricsOtelEnabled = configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED); - otelResourceAttributes = - getHashMap(configProvider.getList(OTEL_RESOURCE_ATTRIBUTES), OTEL_RESOURCE_ATTRIBUTES, "="); + otelResourceAttributes = configProvider.getMergedMap(OTEL_RESOURCE_ATTRIBUTES, '='); + otelMetricsExporter = configProvider.getEnum( OTEL_METRICS_EXPORTER, OtelConfig.Exporter.class, DEFAULT_OTEL_METRICS_EXPORTER, false); @@ -1874,14 +1874,13 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins ? DEFAULT_OTEL_METRIC_EXPORT_INTERVAL : tmpOtelMetricExportInterval; - List tmpOtelExporterOtlpMetricsHeaders = - configProvider.getList(OTEL_EXPORTER_OTLP_METRICS_HEADERS); - otelExporterOtlpMetricsHeaders = - tmpOtelExporterOtlpMetricsHeaders.isEmpty() - ? getHashMap( - configProvider.getList(OTEL_EXPORTER_OTLP_HEADERS), OTEL_EXPORTER_OTLP_HEADERS, "=") - : getHashMap( - tmpOtelExporterOtlpMetricsHeaders, OTEL_EXPORTER_OTLP_METRICS_HEADERS, "="); + Map tmpOtelExporterOtlpMetricsHeaders = + configProvider.getMergedMap(OTEL_EXPORTER_OTLP_METRICS_HEADERS, '='); + if (tmpOtelExporterOtlpMetricsHeaders.isEmpty()) { + tmpOtelExporterOtlpMetricsHeaders = + configProvider.getMergedMap(OTEL_EXPORTER_OTLP_HEADERS, '='); + } + otelExporterOtlpMetricsHeaders = tmpOtelExporterOtlpMetricsHeaders; OtelConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( @@ -5495,30 +5494,6 @@ private static Set convertStringSetToSet( return Collections.unmodifiableSet(result); } - private static Map getHashMap( - List inputAsList, String key, String delimiter) { - Map finalValue = new HashMap<>(); - if (!inputAsList.isEmpty()) { - boolean error = false; - for (String keyvalue : inputAsList) { - int indexOfSplit = keyvalue.indexOf(delimiter); - if (indexOfSplit < 0) { - error = true; - continue; - } - finalValue.put(keyvalue.substring(0, indexOfSplit), keyvalue.substring(indexOfSplit + 1)); - } - if (error) { - log.debug( - "Parsing error occurs for {}, value provided: {}; value taken into account: {}", - key, - inputAsList, - finalValue); - } - } - return finalValue; - } - /** Returns the detected hostname. First tries locally, then using DNS */ static String initHostName() { String possibleHostname; diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 2492563147a..8311f0ea3df 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -493,11 +493,8 @@ class ConfigTest extends DDSpecification { Config config = Config.get(prop) then: - config.otelResourceAttributes.size() == 2 - config.otelResourceAttributes["service.name"] == "my=app=56" - config.otelResourceAttributes["version"] == "1.0.0" - config.otelExporterOtlpMetricsHeaders.size() == 1 - config.otelExporterOtlpMetricsHeaders["key"] == "key" + config.otelResourceAttributes.size() == 0 + config.otelExporterOtlpMetricsHeaders.size() == 0 } @@ -822,6 +819,7 @@ class ConfigTest extends DDSpecification { config.requestHeaderTags == ["*":"http.request.headers."] config.responseHeaderTags == ["*":"http.response.headers."] config.metricsOtelEnabled + config.otelResourceAttributes.size() == 3 config.otelResourceAttributes["service.name"] == "my=app" config.otelResourceAttributes["service.version"] == "1.0.0" config.otelResourceAttributes["deployment.environment"] == "production" diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java index f58a426155e..21d9949ae8c 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java @@ -347,6 +347,10 @@ public List getSpacedList(String key) { } public Map getMergedMap(String key, String... aliases) { + return getMergedMap(key, ':', aliases); + } + + public Map getMergedMap(String key, char keyValueDelimiter, String... aliases) { ConfigMergeResolver mergeResolver = new ConfigMergeResolver(new HashMap<>()); int seqId = NON_DEFAULT_SEQ_ID; @@ -356,7 +360,7 @@ public Map getMergedMap(String key, String... aliases) { // We reverse iterate to allow overrides for (int i = sources.length - 1; 0 <= i; i--) { String value = sources[i].get(key, aliases); - Map parsedMap = ConfigConverter.parseMap(value, key); + Map parsedMap = ConfigConverter.parseMap(value, key, keyValueDelimiter); if (!parsedMap.isEmpty()) { if (collectConfig) { From 7bb9e0c071dca630d9c19ce0b819aaf46c253b9e Mon Sep 17 00:00:00 2001 From: cecile <32452337+cecile75@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:15:35 +0100 Subject: [PATCH 10/38] Update dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java Co-authored-by: mhlidd --- .../src/main/java/datadog/trace/api/ConfigDefaults.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 1d221c7d2e8..7ab2a11ed4e 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -108,8 +108,8 @@ public final class ConfigDefaults { static final Integer DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; // WARNING: This defies the OpenTelemetry specification’s default value of 30000 (30s) static final Integer DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT = 7500; - static final OtelConfig.Protocol DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = - OtelConfig.Protocol.GRPC; + static final Protocol DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = + Protocol.GRPC; static final int DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = 10000; static final int DEFAULT_DOGSTATSD_START_DELAY = 15; // seconds From 781cbba5a3e3e17f51d7cb1a3cfbd963a766f077 Mon Sep 17 00:00:00 2001 From: cecile <32452337+cecile75@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:15:49 +0100 Subject: [PATCH 11/38] Update dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java Co-authored-by: mhlidd --- .../src/main/java/datadog/trace/api/ConfigDefaults.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 7ab2a11ed4e..86fee5073de 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -103,7 +103,7 @@ public final class ConfigDefaults { static final int DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_LIMIT = 10; static final boolean DEFAULT_METRICS_OTEL_ENABLED = false; - static final OtelConfig.Exporter DEFAULT_OTEL_METRICS_EXPORTER = OtelConfig.Exporter.OTLP; + static final Exporter DEFAULT_OTEL_METRICS_EXPORTER = Exporter.OTLP; // WARNING: This defies the OpenTelemetry specification’s default value of 60000 (60s) static final Integer DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; // WARNING: This defies the OpenTelemetry specification’s default value of 30000 (30s) From 7c05b8a46aef24c89ecebf3cd34395e36bdec894 Mon Sep 17 00:00:00 2001 From: cecile <32452337+cecile75@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:16:01 +0100 Subject: [PATCH 12/38] Update dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java Co-authored-by: mhlidd --- .../src/main/java/datadog/trace/api/ConfigDefaults.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 86fee5073de..e7b4fc1c759 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -5,7 +5,8 @@ import static datadog.trace.api.TracePropagationStyle.TRACECONTEXT; import static java.util.Arrays.asList; -import datadog.trace.api.config.OtelConfig; +import datadog.trace.api.config.OtelConfig.Exporter; +import datadog.trace.api.config.OtelConfig.Protocol; import java.util.Arrays; import java.util.BitSet; import java.util.HashSet; From 7924cedb89ec4dae377952e729d2ac0e76a6f4e5 Mon Sep 17 00:00:00 2001 From: cecile <32452337+cecile75@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:18:38 +0100 Subject: [PATCH 13/38] remove duplicate env vars Co-authored-by: mhlidd --- metadata/supported-configurations.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index 85ede150fc5..ce5af9856b1 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -1360,10 +1360,6 @@ "OTEL_TRACES_EXPORTER": ["A"], "OTEL_TRACES_SAMPLER_ARG": ["A"], "OTEL_TRACES_SAMPLER": ["A"], - "OTEL_TRACES_SAMPLER_ARG": ["A"], - "OTEL_TRACES_SAMPLER": ["A"], - "OTEL_RESOURCE_ATTRIBUTES": ["A"], - "OTEL_METRICS_EXPORTER": ["A"], "OTEL_METRIC_EXPORT_INTERVAL": ["A"], "OTEL_METRIC_EXPORT_TIMEOUT": ["A"], "OTEL_EXPORTER_OTLP_ENDPOINT": ["A"], From dd223a390144f270e45dfd0ba9f36466b412674e Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:46:23 +0100 Subject: [PATCH 14/38] Fix spotlessss after commits from github --- .../src/main/java/datadog/trace/api/ConfigDefaults.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index e7b4fc1c759..87ff885a0b1 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -109,8 +109,7 @@ public final class ConfigDefaults { static final Integer DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; // WARNING: This defies the OpenTelemetry specification’s default value of 30000 (30s) static final Integer DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT = 7500; - static final Protocol DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = - Protocol.GRPC; + static final Protocol DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = Protocol.GRPC; static final int DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = 10000; static final int DEFAULT_DOGSTATSD_START_DELAY = 15; // seconds From 666e13af8476e635bc6734f4147b3a47bd96c936 Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:12:42 +0100 Subject: [PATCH 15/38] Refactor generic otel config --- .../datadog/trace/api/ConfigDefaults.java | 6 +- ...OtelConfig.java => OtelMetricsConfig.java} | 4 +- .../main/java/datadog/trace/api/Config.java | 73 ++++----- .../datadog/trace/api/ConfigTest.groovy | 151 ++++++++++++------ .../provider/OtelEnvironmentConfigSource.java | 54 +++++-- 5 files changed, 176 insertions(+), 112 deletions(-) rename dd-trace-api/src/main/java/datadog/trace/api/config/{OtelConfig.java => OtelMetricsConfig.java} (96%) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 87ff885a0b1..328af2ac58a 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -5,8 +5,8 @@ import static datadog.trace.api.TracePropagationStyle.TRACECONTEXT; import static java.util.Arrays.asList; -import datadog.trace.api.config.OtelConfig.Exporter; -import datadog.trace.api.config.OtelConfig.Protocol; +import datadog.trace.api.config.OtelMetricsConfig.Exporter; +import datadog.trace.api.config.OtelMetricsConfig.Protocol; import java.util.Arrays; import java.util.BitSet; import java.util.HashSet; @@ -103,7 +103,7 @@ public final class ConfigDefaults { static final boolean DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_ENABLED = false; static final int DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_LIMIT = 10; - static final boolean DEFAULT_METRICS_OTEL_ENABLED = false; + public static final boolean DEFAULT_METRICS_OTEL_ENABLED = false; static final Exporter DEFAULT_OTEL_METRICS_EXPORTER = Exporter.OTLP; // WARNING: This defies the OpenTelemetry specification’s default value of 60000 (60s) static final Integer DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java similarity index 96% rename from dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java rename to dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java index 8d24805dfd8..c1243ad0ac6 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java @@ -1,6 +1,6 @@ package datadog.trace.api.config; -public final class OtelConfig { +public final class OtelMetricsConfig { public static final String METRICS_OTEL_ENABLED = "metrics.otel.enabled"; public static final String OTEL_RESOURCE_ATTRIBUTES = "otel.resource.attributes"; @@ -43,5 +43,5 @@ public enum Protocol { HTTP_JSON; } - private OtelConfig() {} + private OtelMetricsConfig() {} } diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 4043b3ca5b4..46d190c0a2e 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -443,23 +443,22 @@ import static datadog.trace.api.config.JmxFetchConfig.JMX_TAGS; import static datadog.trace.api.config.LlmObsConfig.LLMOBS_AGENTLESS_ENABLED; import static datadog.trace.api.config.LlmObsConfig.LLMOBS_ML_APP; -import static datadog.trace.api.config.OtelConfig.METRICS_OTEL_ENABLED; -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_ENDPOINT; -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_HEADERS; -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT; -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS; -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE; -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_PROTOCOL; -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_TIMEOUT; -import static datadog.trace.api.config.OtelConfig.OTEL_METRICS_EXPORTER; -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_DEFAULT_ENDPOINT_GRPC_PORT; -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_DEFAULT_ENDPOINT_HTTP_PORT; -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX; -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_INTERVAL; -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_TIMEOUT; -import static datadog.trace.api.config.OtelConfig.OTEL_RESOURCE_ATTRIBUTES; +import static datadog.trace.api.config.OtelMetricsConfig.METRICS_OTEL_ENABLED; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_ENDPOINT; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_HEADERS; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_PROTOCOL; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_TIMEOUT; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRICS_EXPORTER; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_DEFAULT_ENDPOINT_GRPC_PORT; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_DEFAULT_ENDPOINT_HTTP_PORT; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_INTERVAL; +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_TIMEOUT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_API_KEY_FILE_OLD; @@ -688,7 +687,7 @@ import datadog.environment.SystemProperties; import datadog.trace.api.civisibility.CiVisibilityWellKnownTags; import datadog.trace.api.config.GeneralConfig; -import datadog.trace.api.config.OtelConfig; +import datadog.trace.api.config.OtelMetricsConfig; import datadog.trace.api.config.ProfilingConfig; import datadog.trace.api.config.TracerConfig; import datadog.trace.api.iast.IastContext; @@ -914,15 +913,14 @@ public static String getHostName() { private final int jmxFetchMultipleRuntimeServicesLimit; private final boolean metricsOtelEnabled; - private final Map otelResourceAttributes; - private final OtelConfig.Exporter otelMetricsExporter; + private final OtelMetricsConfig.Exporter otelMetricsExporter; private final Integer otelMetricExportInterval; private final Integer otelMetricExportTimeout; private final String otelExporterOtlpMetricsEndpoint; private final Map otelExporterOtlpMetricsHeaders; - private final OtelConfig.Protocol otelExporterOtlpMetricsProtocol; + private final OtelMetricsConfig.Protocol otelExporterOtlpMetricsProtocol; private final Integer otelExporterOtlpMetricsTimeout; - private final OtelConfig.Temporality otelExporterOtlpMetricsTemporalityPreference; + private final OtelMetricsConfig.Temporality otelExporterOtlpMetricsTemporalityPreference; // These values are default-ed to those of jmx fetch values as needed private final boolean healthMetricsEnabled; @@ -1869,11 +1867,10 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins metricsOtelEnabled = configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED); - otelResourceAttributes = configProvider.getMergedMap(OTEL_RESOURCE_ATTRIBUTES, '='); otelMetricsExporter = configProvider.getEnum( - OTEL_METRICS_EXPORTER, OtelConfig.Exporter.class, DEFAULT_OTEL_METRICS_EXPORTER, false); + OTEL_METRICS_EXPORTER, OtelMetricsConfig.Exporter.class, DEFAULT_OTEL_METRICS_EXPORTER, false); Integer tmpOtelMetricExportTimeout = configProvider.getInteger(OTEL_METRIC_EXPORT_TIMEOUT); otelMetricExportTimeout = @@ -1895,14 +1892,14 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins } otelExporterOtlpMetricsHeaders = tmpOtelExporterOtlpMetricsHeaders; - OtelConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = + OtelMetricsConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( - OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OtelConfig.Protocol.class, null, false, "/", "_"); + OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OtelMetricsConfig.Protocol.class, null, false, "/", "_"); if (tmpOtelExporterOtlpMetricsProtocol == null) { tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( OTEL_EXPORTER_OTLP_PROTOCOL, - OtelConfig.Protocol.class, + OtelMetricsConfig.Protocol.class, DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, false, "/", @@ -1916,7 +1913,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins String tmpOtelExporterOtlpMetricsEndpoint = configProvider.getString(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT); if (tmpOtelExporterOtlpMetricsEndpoint == null) { - boolean isHttp = !otelExporterOtlpMetricsProtocol.equals(OtelConfig.Protocol.GRPC); + boolean isHttp = !otelExporterOtlpMetricsProtocol.equals(OtelMetricsConfig.Protocol.GRPC); String tmpOtelExporterOtlpEndpoint = configProvider.getString(OTEL_EXPORTER_OTLP_ENDPOINT); if (null == tmpOtelExporterOtlpEndpoint) { String endpointHost = agentHost.isEmpty() ? DEFAULT_AGENT_HOST : agentHost; @@ -1951,14 +1948,12 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins otelExporterOtlpMetricsTemporalityPreference = configProvider.getEnum( OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, - OtelConfig.Temporality.class, - OtelConfig.Temporality.DELTA, + OtelMetricsConfig.Temporality.class, + OtelMetricsConfig.Temporality.DELTA, false); // Runtime metrics are disabled if Otel metrics are enabled and the metrics exporter is none - runtimeMetricsEnabled = - (!metricsOtelEnabled || !otelMetricsExporter.equals(OtelConfig.Exporter.NONE)) - && configProvider.getBoolean(RUNTIME_METRICS_ENABLED, true); + runtimeMetricsEnabled = configProvider.getBoolean(RUNTIME_METRICS_ENABLED, true); jmxFetchEnabled = runtimeMetricsEnabled @@ -5100,11 +5095,7 @@ public boolean isMetricsOtelEnabled() { return metricsOtelEnabled; } - public Map getOtelResourceAttributes() { - return otelResourceAttributes; - } - - public OtelConfig.Exporter getOtelMetricsExporter() { + public OtelMetricsConfig.Exporter getOtelMetricsExporter() { return otelMetricsExporter; } @@ -5124,7 +5115,7 @@ public Map getOtelExporterOtlpMetricsHeaders() { return otelExporterOtlpMetricsHeaders; } - public OtelConfig.Protocol getOtelExporterOtlpMetricsProtocol() { + public OtelMetricsConfig.Protocol getOtelExporterOtlpMetricsProtocol() { return otelExporterOtlpMetricsProtocol; } @@ -5132,7 +5123,7 @@ public Integer getOtelExporterOtlpMetricsTimeout() { return otelExporterOtlpMetricsTimeout; } - public OtelConfig.Temporality getOtelExporterOtlpMetricsTemporalityPreference() { + public OtelMetricsConfig.Temporality getOtelExporterOtlpMetricsTemporalityPreference() { return otelExporterOtlpMetricsTemporalityPreference; } @@ -6126,8 +6117,6 @@ public String toString() { + aiGuardEndpoint + ", metricsOtelEnabled=" + metricsOtelEnabled - + ", otelResourceAttributes=" - + otelResourceAttributes + ", otelMetricsExporter=" + otelMetricsExporter + ", otelMetricExportInterval=" diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 47291f3e493..a1a0c52e8a8 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -6,7 +6,7 @@ import datadog.trace.bootstrap.config.provider.ConfigConverter import datadog.trace.bootstrap.config.provider.ConfigProvider import datadog.trace.test.util.DDSpecification import datadog.trace.util.throwable.FatalAgentMisconfigurationError - +import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_OTEL_ENABLED import static datadog.trace.api.ConfigDefaults.DEFAULT_HTTP_CLIENT_ERROR_STATUSES import static datadog.trace.api.ConfigDefaults.DEFAULT_HTTP_SERVER_ERROR_STATUSES import static datadog.trace.api.ConfigDefaults.DEFAULT_PARTIAL_FLUSH_MIN_SPANS @@ -58,7 +58,6 @@ import static datadog.trace.api.config.GeneralConfig.SITE import static datadog.trace.api.config.GeneralConfig.TAGS import static datadog.trace.api.config.GeneralConfig.TRACER_METRICS_IGNORED_RESOURCES import static datadog.trace.api.config.GeneralConfig.VERSION -import static datadog.trace.api.config.GeneralConfig.RUNTIME_METRICS_ENABLED import static datadog.trace.api.config.GeneralConfig.SSI_INJECTION_ENABLED import static datadog.trace.api.config.GeneralConfig.SSI_INJECTION_FORCE import static datadog.trace.api.config.GeneralConfig.INSTRUMENTATION_SOURCE @@ -138,26 +137,26 @@ import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_OPERATION_RUL import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_SERVICE_RULES import static datadog.trace.api.config.TracerConfig.TRACE_X_DATADOG_TAGS_MAX_LENGTH import static datadog.trace.api.config.TracerConfig.WRITER_TYPE -import static datadog.trace.api.config.OtelConfig.Protocol.GRPC -import static datadog.trace.api.config.OtelConfig.Protocol.HTTP_PROTOBUF -import static datadog.trace.api.config.OtelConfig.Protocol.HTTP_JSON -import static datadog.trace.api.config.OtelConfig.Exporter.OTLP -import static datadog.trace.api.config.OtelConfig.Temporality.CUMULATIVE -import static datadog.trace.api.config.OtelConfig.Temporality.DELTA -import static datadog.trace.api.config.OtelConfig.METRICS_OTEL_ENABLED -import static datadog.trace.api.config.OtelConfig.OTEL_RESOURCE_ATTRIBUTES -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_ENDPOINT -import static datadog.trace.api.config.OtelConfig.OTEL_METRICS_EXPORTER -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_INTERVAL -import static datadog.trace.api.config.OtelConfig.OTEL_METRIC_EXPORT_TIMEOUT -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_PROTOCOL -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_TIMEOUT -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_HEADERS -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT -import static datadog.trace.api.config.OtelConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE +import static datadog.trace.api.config.OtelMetricsConfig.Protocol.GRPC +import static datadog.trace.api.config.OtelMetricsConfig.Protocol.HTTP_PROTOBUF +import static datadog.trace.api.config.OtelMetricsConfig.Protocol.HTTP_JSON +import static datadog.trace.api.config.OtelMetricsConfig.Exporter.OTLP +import static datadog.trace.api.config.OtelMetricsConfig.Temporality.CUMULATIVE +import static datadog.trace.api.config.OtelMetricsConfig.Temporality.DELTA +import static datadog.trace.api.config.OtelMetricsConfig.METRICS_OTEL_ENABLED +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_RESOURCE_ATTRIBUTES +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_ENDPOINT +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRICS_EXPORTER +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_INTERVAL +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_TIMEOUT +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_PROTOCOL +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_TIMEOUT +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_HEADERS +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT +import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE import datadog.trace.config.inversion.ConfigHelper class ConfigTest extends DDSpecification { @@ -308,7 +307,6 @@ class ConfigTest extends DDSpecification { prop.setProperty(JDK_SOCKET_ENABLED, "false") prop.setProperty(METRICS_OTEL_ENABLED, "True") - prop.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app,service.version=1.0.0,deployment.environment=production") prop.setProperty(OTEL_METRICS_EXPORTER, "otlp") prop.setProperty(OTEL_METRIC_EXPORT_INTERVAL, "11000") prop.setProperty(OTEL_METRIC_EXPORT_TIMEOUT, "9000") @@ -415,9 +413,6 @@ class ConfigTest extends DDSpecification { config.jdkSocketEnabled == false config.metricsOtelEnabled - config.otelResourceAttributes["service.name"] == "my=app" - config.otelResourceAttributes["service.version"] == "1.0.0" - config.otelResourceAttributes["deployment.environment"] == "production" config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 11000 config.otelMetricExportTimeout == 9000 @@ -435,7 +430,6 @@ class ConfigTest extends DDSpecification { def prop = new Properties() prop.setProperty(METRICS_OTEL_ENABLED, "youhou") - prop.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service") prop.setProperty(OTEL_METRICS_EXPORTER, "invalid") prop.setProperty(OTEL_METRIC_EXPORT_INTERVAL, "-1") prop.setProperty(OTEL_METRIC_EXPORT_TIMEOUT, "invalid") @@ -450,7 +444,6 @@ class ConfigTest extends DDSpecification { then: !config.metricsOtelEnabled - config.otelResourceAttributes == [:] config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 10000 config.otelMetricExportTimeout == 7500 @@ -461,7 +454,6 @@ class ConfigTest extends DDSpecification { config.otelExporterOtlpMetricsTemporalityPreference == DELTA } - def "otel metrics: default values when not set"() { setup: def prop = new Properties() @@ -471,7 +463,6 @@ class ConfigTest extends DDSpecification { then: !config.metricsOtelEnabled - config.otelResourceAttributes == [:] config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 10000 config.otelMetricExportTimeout == 7500 @@ -486,30 +477,92 @@ class ConfigTest extends DDSpecification { def "otel metrics: check syntax for attributes and headers"() { setup: def prop = new Properties() - prop.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app=56,version=1.0.0,deployment:environment") prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "api,key=key") when: Config config = Config.get(prop) then: - config.otelResourceAttributes.size() == 0 config.otelExporterOtlpMetricsHeaders.size() == 0 } + def "otel generic config via system properties - metrics enabled"() { + setup: + System.setProperty(PREFIX + METRICS_OTEL_ENABLED, "true") + System.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") + System.setProperty("otel.log.level", "warning") + + when: + Config config = new Config() + + then: + config.serviceName == "my=app" + config.version == "1.0.0" + config.env == "production" + config.tags.size() == 3 + config.tags["message"] == "blahblah" + config.tags["env"] == "production" + config.tags["version"] == "1.0.0" + config.logLevel == "warning" + } - def "otel metrics enabled, exporter none => runtime metrics should be disabled "() { + def "otel generic config via system properties - trace enabled"() { setup: - def prop = new Properties() - prop.setProperty(METRICS_OTEL_ENABLED, "true") - prop.setProperty(OTEL_METRICS_EXPORTER, "none") - prop.setProperty(PREFIX + RUNTIME_METRICS_ENABLED, "true") + System.setProperty(PREFIX + TRACE_OTEL_ENABLED, "true") + System.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") + System.setProperty("otel.log.level", "warning") when: - Config config = Config.get(prop) + Config config = new Config() then: - !config.runtimeMetricsEnabled + config.serviceName == "my=app" + config.version == "1.0.0" + config.env == "production" + config.tags.size() == 3 + config.tags["message"] == "blahblah" + config.tags["env"] == "production" + config.tags["version"] == "1.0.0" + config.logLevel == "warning" + } + + + def "otel generic config via env var - metrics enabled"() { + setup: + environmentVariables.set(DD_METRICS_OTEL_ENABLED_ENV, "true") + environmentVariables.set(OTEL_RESOURCE_ATTRIBUTES_ENV, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") + environmentVariables.set("OTEL_LOG_LEVEL", "error") + when: + Config config = new Config() + + then: + config.serviceName == "my=app" + config.version == "1.0.0" + config.env == "production" + config.tags.size() == 3 + config.tags["message"] == "blahblah" + config.tags["env"] == "production" + config.tags["version"] == "1.0.0" + config.logLevel == "error" + } + + def "otel generic config via env var - traces enabled"() { + setup: + environmentVariables.set("DD_TRACE_OTEL_ENABLED", "true") + environmentVariables.set(OTEL_RESOURCE_ATTRIBUTES_ENV, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") + environmentVariables.set("OTEL_LOG_LEVEL", "error") + when: + Config config = new Config() + + then: + config.serviceName == "my=app" + config.version == "1.0.0" + config.env == "production" + config.tags.size() == 3 + config.tags["message"] == "blahblah" + config.tags["env"] == "production" + config.tags["version"] == "1.0.0" + config.logLevel == "error" } def "otel metrics: fallback keys"() { @@ -531,6 +584,7 @@ class ConfigTest extends DDSpecification { config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" config.otelExporterOtlpMetricsTimeout == 1000 } + def "otel metrics: fallback key endpoint"() { setup: def prop = new Properties() @@ -679,8 +733,8 @@ class ConfigTest extends DDSpecification { config.prioritySamplingEnabled == false config.traceResolverEnabled == false config.serviceMapping == [a: "1"] - config.mergedSpanTags == [b: "2", c: "3"] - config.mergedJmxTags == [b: "2", d: "4", (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName] + config.mergedSpanTags == [b: "2", c: "3", env: "production", version:"1.0.0"] + config.mergedJmxTags == [b: "2", d: "4", (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName, env: "production", version:"1.0.0"] config.requestHeaderTags == [e: "five"] config.baggageMapping == [f: "six", g: "g"] config.httpServerErrorStatuses == toBitSet((122..457)) @@ -720,7 +774,7 @@ class ConfigTest extends DDSpecification { config.profilingEnabled == true config.profilingUrl == "new url" - config.mergedProfilingTags == [b: "2", f: "6", (HOST_TAG): "test-host", (RUNTIME_ID_TAG): config.getRuntimeId(), (RUNTIME_VERSION_TAG): config.getRuntimeVersion(), (SERVICE_TAG): config.serviceName, (LANGUAGE_TAG_KEY): LANGUAGE_TAG_VALUE] + config.mergedProfilingTags == [b: "2", f: "6", (HOST_TAG): "test-host", (RUNTIME_ID_TAG): config.getRuntimeId(), (RUNTIME_VERSION_TAG): config.getRuntimeVersion(), (SERVICE_TAG): config.serviceName, (LANGUAGE_TAG_KEY): LANGUAGE_TAG_VALUE, env: "production", version:"1.0.0"] config.profilingStartDelay == 1111 config.profilingStartForceFirst == true config.profilingUploadPeriod == 1112 @@ -757,9 +811,8 @@ class ConfigTest extends DDSpecification { config.xDatadogTagsMaxLength == 128 config.metricsOtelEnabled - config.otelResourceAttributes["service.name"] == "my=app" - config.otelResourceAttributes["service.version"] == "1.0.0" - config.otelResourceAttributes["deployment.environment"] == "production" + config.version == "1.0.0" + config.env == "production" config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 11000 config.otelMetricExportTimeout == 9000 @@ -819,10 +872,10 @@ class ConfigTest extends DDSpecification { config.requestHeaderTags == ["*":"http.request.headers."] config.responseHeaderTags == ["*":"http.response.headers."] config.metricsOtelEnabled - config.otelResourceAttributes.size() == 3 - config.otelResourceAttributes["service.name"] == "my=app" - config.otelResourceAttributes["service.version"] == "1.0.0" - config.otelResourceAttributes["deployment.environment"] == "production" + //config.otelResourceAttributes.size() == 3 + //config.otelResourceAttributes["service.name"] == "my=app" + //config.otelResourceAttributes["service.version"] == "1.0.0" + //config.otelResourceAttributes["deployment.environment"] == "production" config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 11000 config.otelMetricExportTimeout == 9000 diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java index 566c5ac5dc4..8eb5000755e 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java @@ -1,5 +1,6 @@ package datadog.trace.bootstrap.config.provider; +import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_TRACE_OTEL_ENABLED; import static datadog.trace.api.config.GeneralConfig.ENV; import static datadog.trace.api.config.GeneralConfig.LOG_LEVEL; @@ -7,6 +8,7 @@ import static datadog.trace.api.config.GeneralConfig.SERVICE_NAME; import static datadog.trace.api.config.GeneralConfig.TAGS; import static datadog.trace.api.config.GeneralConfig.VERSION; +import static datadog.trace.api.config.OtelMetricsConfig.METRICS_OTEL_ENABLED; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_ENABLED; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_EXTENSIONS_PATH; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_OTEL_ENABLED; @@ -71,32 +73,26 @@ public ConfigOrigin origin() { } OtelEnvironmentConfigSource(Properties datadogConfigFile) { - this.enabled = traceOtelEnabled(); + this.enabled = traceOtelEnabled() || metricsOtelEnabled(); this.datadogConfigFile = datadogConfigFile; if (enabled) { - setupOteEnvironment(); + setupOtelEnvironment(); } } - private void setupOteEnvironment() { + private void setupOtelEnvironment() { - // only applies when OTEL is enabled by default (otherwise TRACE_OTEL_ENABLED takes precedence) + // only applies when OTEL is enabled by default String sdkDisabled = getOtelProperty("otel.sdk.disabled", "dd." + TRACE_OTEL_ENABLED); if ("true".equalsIgnoreCase(sdkDisabled)) { capture(TRACE_OTEL_ENABLED, "false"); + capture(METRICS_OTEL_ENABLED, "false"); return; } - - String serviceName = getOtelProperty("otel.service.name", "dd." + SERVICE_NAME); String logLevel = getOtelProperty("otel.log.level", "dd." + LOG_LEVEL); - String propagators = getOtelProperty("otel.propagators", "dd." + TRACE_PROPAGATION_STYLE); - String tracesSampler = getOtelProperty("otel.traces.sampler", "dd." + TRACE_SAMPLE_RATE); String resourceAttributes = getOtelProperty("otel.resource.attributes", "dd." + TAGS); - String requestHeaders = getOtelHeaders("request-headers", "dd." + REQUEST_HEADER_TAGS); - String responseHeaders = getOtelHeaders("response-headers", "dd." + RESPONSE_HEADER_TAGS); - String extensions = getOtelProperty("otel.javaagent.extensions", "dd." + TRACE_EXTENSIONS_PATH); - + String serviceName = getOtelProperty("otel.service.name", "dd." + SERVICE_NAME); if (null != resourceAttributes) { Map attributeMap = parseOtelMap(resourceAttributes); capture(SERVICE_NAME, attributeMap.remove("service.name")); @@ -104,15 +100,28 @@ private void setupOteEnvironment() { capture(ENV, attributeMap.remove("deployment.environment")); capture(TAGS, renderDatadogMap(attributeMap, 10)); } - capture(LOG_LEVEL, logLevel); capture(SERVICE_NAME, serviceName); + mapDataCollection("logs"); // check setting, but no need to capture it + + if (traceOtelEnabled()) { + setupOtelTraceEnvironment(); + } + if (metricsOtelEnabled()) { + setupOtelMetricsEnvironment(); + } + } + + private void setupOtelTraceEnvironment() { + String propagators = getOtelProperty("otel.propagators", "dd." + TRACE_PROPAGATION_STYLE); + String tracesSampler = getOtelProperty("otel.traces.sampler", "dd." + TRACE_SAMPLE_RATE); + + String requestHeaders = getOtelHeaders("request-headers", "dd." + REQUEST_HEADER_TAGS); + String responseHeaders = getOtelHeaders("response-headers", "dd." + RESPONSE_HEADER_TAGS); + String extensions = getOtelProperty("otel.javaagent.extensions", "dd." + TRACE_EXTENSIONS_PATH); capture(TRACE_PROPAGATION_STYLE, mapPropagationStyle(propagators)); capture(TRACE_SAMPLE_RATE, mapSampleRate(tracesSampler)); - capture(TRACE_ENABLED, mapDataCollection("traces")); - capture(RUNTIME_METRICS_ENABLED, mapDataCollection("metrics")); - mapDataCollection("logs"); // check setting, but no need to capture it capture(REQUEST_HEADER_TAGS, mapHeaderTags("http.request.header.", requestHeaders)); capture(RESPONSE_HEADER_TAGS, mapHeaderTags("http.response.header.", responseHeaders)); @@ -120,6 +129,10 @@ private void setupOteEnvironment() { capture(TRACE_EXTENSIONS_PATH, extensions); } + private void setupOtelMetricsEnvironment() { + capture(RUNTIME_METRICS_ENABLED, mapDataCollection("metrics")); + } + private boolean traceOtelEnabled() { String enabled = getDatadogProperty("dd." + TRACE_OTEL_ENABLED); if (null != enabled) { @@ -129,6 +142,15 @@ private boolean traceOtelEnabled() { } } + private boolean metricsOtelEnabled() { + String enabled = getDatadogProperty("dd." + METRICS_OTEL_ENABLED); + if (null != enabled) { + return Boolean.parseBoolean(enabled); + } else { + return DEFAULT_METRICS_OTEL_ENABLED; + } + } + /** * Gets an OpenTelemetry property. * From c5b3923ad0fef1369857bc5adbccfc6023d5107e Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:21:18 +0100 Subject: [PATCH 16/38] Clean --- .../src/main/java/datadog/trace/api/Config.java | 12 ++++++++++-- .../test/groovy/datadog/trace/api/ConfigTest.groovy | 4 ---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 46d190c0a2e..e843d54552a 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -1870,7 +1870,10 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins otelMetricsExporter = configProvider.getEnum( - OTEL_METRICS_EXPORTER, OtelMetricsConfig.Exporter.class, DEFAULT_OTEL_METRICS_EXPORTER, false); + OTEL_METRICS_EXPORTER, + OtelMetricsConfig.Exporter.class, + DEFAULT_OTEL_METRICS_EXPORTER, + false); Integer tmpOtelMetricExportTimeout = configProvider.getInteger(OTEL_METRIC_EXPORT_TIMEOUT); otelMetricExportTimeout = @@ -1894,7 +1897,12 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins OtelMetricsConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( - OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OtelMetricsConfig.Protocol.class, null, false, "/", "_"); + OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, + OtelMetricsConfig.Protocol.class, + null, + false, + "/", + "_"); if (tmpOtelExporterOtlpMetricsProtocol == null) { tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index a1a0c52e8a8..1d0df5052cc 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -872,10 +872,6 @@ class ConfigTest extends DDSpecification { config.requestHeaderTags == ["*":"http.request.headers."] config.responseHeaderTags == ["*":"http.response.headers."] config.metricsOtelEnabled - //config.otelResourceAttributes.size() == 3 - //config.otelResourceAttributes["service.name"] == "my=app" - //config.otelResourceAttributes["service.version"] == "1.0.0" - //config.otelResourceAttributes["deployment.environment"] == "production" config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 11000 config.otelMetricExportTimeout == 9000 From 2788bddb111adbad1a11a1e5a60476e620edc4c6 Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:44:25 +0100 Subject: [PATCH 17/38] Re adapt class name for graalVM --- .../NativeImageGeneratorRunnerInstrumentation.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java index 593ad9e4f42..8cf35959475 100644 --- a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java +++ b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java @@ -84,8 +84,8 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[ + "datadog.trace.api.ConfigDefaults:build_time," + "datadog.trace.api.ConfigOrigin:build_time," + "datadog.trace.api.ConfigSetting:build_time," - + "datadog.trace.api.config.OtelConfig$Protocol:build_time," - + "datadog.trace.api.config.OtelConfig$Exporter:build_time," + + "datadog.trace.api.config.OtelMetricsConfig$Protocol:build_time," + + "datadog.trace.api.config.OtelMetricsConfig$Exporter:build_time," + "datadog.trace.api.EventTracker:build_time," + "datadog.trace.api.InstrumenterConfig:build_time," + "datadog.trace.api.Functions:build_time," From 8ef12862989a234de5ed0c568ffcbe6bf48ab49f Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 3 Nov 2025 17:38:20 +0100 Subject: [PATCH 18/38] renaming leftover --- dd-trace-api/build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dd-trace-api/build.gradle.kts b/dd-trace-api/build.gradle.kts index 490da71e4d7..e0042270947 100644 --- a/dd-trace-api/build.gradle.kts +++ b/dd-trace-api/build.gradle.kts @@ -63,9 +63,9 @@ val excludedClassesCoverage by extra( "datadog.trace.payloadtags.PayloadTagsData", "datadog.trace.payloadtags.PayloadTagsData.PathAndValue", "datadog.trace.api.llmobs.LLMObsTags", - "datadog.trace.api.config.OtelConfig.Protocol", - "datadog.trace.api.config.OtelConfig.Temporality", - "datadog.trace.api.config.OtelConfig.Exporter", + "datadog.trace.api.config.OtelMetricsConfig.Protocol", + "datadog.trace.api.config.OtelMetricsConfig.Temporality", + "datadog.trace.api.config.OtelMetricsConfig.Exporter", ) ) From 28394a230055324beea67a8d39c66162a549e378 Mon Sep 17 00:00:00 2001 From: cecile75 <32452337+cecile75@users.noreply.github.com> Date: Mon, 3 Nov 2025 19:47:16 +0100 Subject: [PATCH 19/38] Fix runtime metrics --- .../config/provider/OtelEnvironmentConfigSource.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java index 8eb5000755e..00c61666784 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java @@ -102,37 +102,28 @@ private void setupOtelEnvironment() { } capture(LOG_LEVEL, logLevel); capture(SERVICE_NAME, serviceName); + capture(RUNTIME_METRICS_ENABLED, mapDataCollection("metrics")); mapDataCollection("logs"); // check setting, but no need to capture it if (traceOtelEnabled()) { setupOtelTraceEnvironment(); } - if (metricsOtelEnabled()) { - setupOtelMetricsEnvironment(); - } } private void setupOtelTraceEnvironment() { String propagators = getOtelProperty("otel.propagators", "dd." + TRACE_PROPAGATION_STYLE); String tracesSampler = getOtelProperty("otel.traces.sampler", "dd." + TRACE_SAMPLE_RATE); - String requestHeaders = getOtelHeaders("request-headers", "dd." + REQUEST_HEADER_TAGS); String responseHeaders = getOtelHeaders("response-headers", "dd." + RESPONSE_HEADER_TAGS); String extensions = getOtelProperty("otel.javaagent.extensions", "dd." + TRACE_EXTENSIONS_PATH); capture(TRACE_PROPAGATION_STYLE, mapPropagationStyle(propagators)); capture(TRACE_SAMPLE_RATE, mapSampleRate(tracesSampler)); capture(TRACE_ENABLED, mapDataCollection("traces")); - capture(REQUEST_HEADER_TAGS, mapHeaderTags("http.request.header.", requestHeaders)); capture(RESPONSE_HEADER_TAGS, mapHeaderTags("http.response.header.", responseHeaders)); - capture(TRACE_EXTENSIONS_PATH, extensions); } - private void setupOtelMetricsEnvironment() { - capture(RUNTIME_METRICS_ENABLED, mapDataCollection("metrics")); - } - private boolean traceOtelEnabled() { String enabled = getDatadogProperty("dd." + TRACE_OTEL_ENABLED); if (null != enabled) { From d4bc02d8549bff3b511344d77ee7e06220e45806 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Tue, 4 Nov 2025 21:57:20 +0000 Subject: [PATCH 20/38] Include OtelMetricsConfig$Temporality along with the other new OTel metrics enums --- .../nativeimage/NativeImageGeneratorRunnerInstrumentation.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java index 8cf35959475..97ffd32f4d6 100644 --- a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java +++ b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java @@ -84,8 +84,9 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[ + "datadog.trace.api.ConfigDefaults:build_time," + "datadog.trace.api.ConfigOrigin:build_time," + "datadog.trace.api.ConfigSetting:build_time," - + "datadog.trace.api.config.OtelMetricsConfig$Protocol:build_time," + "datadog.trace.api.config.OtelMetricsConfig$Exporter:build_time," + + "datadog.trace.api.config.OtelMetricsConfig$Protocol:build_time," + + "datadog.trace.api.config.OtelMetricsConfig$Temporality:build_time," + "datadog.trace.api.EventTracker:build_time," + "datadog.trace.api.InstrumenterConfig:build_time," + "datadog.trace.api.Functions:build_time," From 0284268e0c265e4d834332f76ced791be1c46af3 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Tue, 4 Nov 2025 22:11:19 +0000 Subject: [PATCH 21/38] Cleanup OTel constants --- .../trace/api/config/OtelMetricsConfig.java | 15 ++++++++------- .../src/main/java/datadog/trace/api/Config.java | 14 +++++++------- .../groovy/datadog/trace/api/ConfigTest.groovy | 13 +++++-------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java index c1243ad0ac6..2e8dce776f3 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java @@ -3,10 +3,11 @@ public final class OtelMetricsConfig { public static final String METRICS_OTEL_ENABLED = "metrics.otel.enabled"; - public static final String OTEL_RESOURCE_ATTRIBUTES = "otel.resource.attributes"; + public static final String OTEL_METRICS_EXPORTER = "otel.metrics.exporter"; public static final String OTEL_METRIC_EXPORT_INTERVAL = "otel.metric.export.interval"; public static final String OTEL_METRIC_EXPORT_TIMEOUT = "otel.metric.export.timeout"; + public static final String OTEL_EXPORTER_OTLP_ENDPOINT = "otel.exporter.otlp.endpoint"; public static final String OTEL_EXPORTER_OTLP_HEADERS = "otel.exporter.otlp.headers"; public static final String OTEL_EXPORTER_OTLP_PROTOCOL = "otel.exporter.otlp.protocol"; @@ -22,25 +23,25 @@ public final class OtelMetricsConfig { public static final String OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = "otel.exporter.otlp.metrics.temporality.preference"; - public static final String OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX = "v1/metrics"; - public static final String OTEL_METRIC_DEFAULT_ENDPOINT_HTTP_PORT = "4318"; - public static final String OTEL_METRIC_DEFAULT_ENDPOINT_GRPC_PORT = "4317"; + public static final String DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX = "v1/metrics"; + public static final String DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT = "4318"; + public static final String DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT = "4317"; public enum Temporality { CUMULATIVE, DELTA, - LOWMEMORY; + LOWMEMORY } public enum Exporter { OTLP, - NONE; + NONE } public enum Protocol { GRPC, HTTP_PROTOBUF, - HTTP_JSON; + HTTP_JSON } private OtelMetricsConfig() {} diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index e843d54552a..db3181e93fa 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -454,9 +454,9 @@ import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_PROTOCOL; import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_TIMEOUT; import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRICS_EXPORTER; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_DEFAULT_ENDPOINT_GRPC_PORT; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_DEFAULT_ENDPOINT_HTTP_PORT; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX; +import static datadog.trace.api.config.OtelMetricsConfig.DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT; +import static datadog.trace.api.config.OtelMetricsConfig.DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT; +import static datadog.trace.api.config.OtelMetricsConfig.DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX; import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_INTERVAL; import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_TIMEOUT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS; @@ -1930,14 +1930,14 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins ? "http://" + endpointHost + ":" - + OTEL_METRIC_DEFAULT_ENDPOINT_HTTP_PORT + + DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT + "/" - + OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX - : "http://" + endpointHost + ":" + OTEL_METRIC_DEFAULT_ENDPOINT_GRPC_PORT; + + DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX + : "http://" + endpointHost + ":" + DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT; } else { tmpOtelExporterOtlpMetricsEndpoint = isHttp - ? tmpOtelExporterOtlpEndpoint.concat(OTEL_METRIC_DEFAULT_ENDPOINT_SUFFIX) + ? tmpOtelExporterOtlpEndpoint.concat(DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX) : tmpOtelExporterOtlpEndpoint; } } diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 1d0df5052cc..bdb552da0d9 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -144,7 +144,6 @@ import static datadog.trace.api.config.OtelMetricsConfig.Exporter.OTLP import static datadog.trace.api.config.OtelMetricsConfig.Temporality.CUMULATIVE import static datadog.trace.api.config.OtelMetricsConfig.Temporality.DELTA import static datadog.trace.api.config.OtelMetricsConfig.METRICS_OTEL_ENABLED -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_RESOURCE_ATTRIBUTES import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_ENDPOINT import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRICS_EXPORTER import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_INTERVAL @@ -194,10 +193,10 @@ class ConfigTest extends DDSpecification { private static final DD_LLMOBS_ML_APP_ENV = "DD_LLMOBS_ML_APP" private static final DD_LLMOBS_AGENTLESS_ENABLED_ENV = "DD_LLMOBS_AGENTLESS_ENABLED" - + private static final OTEL_RESOURCE_ATTRIBUTES_PROP = "otel.resource.attributes" + private static final OTEL_RESOURCE_ATTRIBUTES_ENV = "OTEL_RESOURCE_ATTRIBUTES" private static final DD_METRICS_OTEL_ENABLED_ENV = "DD_METRICS_OTEL_ENABLED" - private static final OTEL_RESOURCE_ATTRIBUTES_ENV = "OTEL_RESOURCE_ATTRIBUTES" private static final OTEL_METRICS_EXPORTER_ENV = "OTEL_METRICS_EXPORTER" private static final OTEL_METRIC_EXPORT_TIMEOUT_ENV = "OTEL_METRIC_EXPORT_TIMEOUT" private static final OTEL_METRIC_EXPORT_INTERVAL_ENV = "OTEL_METRIC_EXPORT_INTERVAL" @@ -207,8 +206,6 @@ class ConfigTest extends DDSpecification { private static final OTEL_EXPORTER_OTLP_METRICS_TIMEOUT_ENV = "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT" private static final OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE_ENV = "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE" - - def setup() { FixedCapturedEnvironment.useFixedEnv([:]) } @@ -489,7 +486,7 @@ class ConfigTest extends DDSpecification { def "otel generic config via system properties - metrics enabled"() { setup: System.setProperty(PREFIX + METRICS_OTEL_ENABLED, "true") - System.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") + System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") System.setProperty("otel.log.level", "warning") when: @@ -509,7 +506,7 @@ class ConfigTest extends DDSpecification { def "otel generic config via system properties - trace enabled"() { setup: System.setProperty(PREFIX + TRACE_OTEL_ENABLED, "true") - System.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") + System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") System.setProperty("otel.log.level", "warning") when: @@ -707,7 +704,7 @@ class ConfigTest extends DDSpecification { System.setProperty(PREFIX + TRACE_X_DATADOG_TAGS_MAX_LENGTH, "128") System.setProperty(PREFIX + METRICS_OTEL_ENABLED, "True") - System.setProperty(OTEL_RESOURCE_ATTRIBUTES, "service.name=my=app,service.version=1.0.0,deployment.environment=production") + System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production") System.setProperty(OTEL_METRICS_EXPORTER, "otlp") System.setProperty(OTEL_METRIC_EXPORT_INTERVAL, "11000") System.setProperty(OTEL_METRIC_EXPORT_TIMEOUT, "9000") From a7186cbe8dd615be60483fc0a73c2d682fcf54b1 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Tue, 4 Nov 2025 22:24:13 +0000 Subject: [PATCH 22/38] Put defaults in consistent location --- .../src/main/java/datadog/trace/api/ConfigDefaults.java | 3 +++ .../java/datadog/trace/api/config/OtelMetricsConfig.java | 4 ---- internal-api/src/main/java/datadog/trace/api/Config.java | 6 +++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 328af2ac58a..5109aceb5b8 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -109,6 +109,9 @@ public final class ConfigDefaults { static final Integer DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; // WARNING: This defies the OpenTelemetry specification’s default value of 30000 (30s) static final Integer DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT = 7500; + static final String DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX = "v1/metrics"; + static final String DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT = "4318"; + static final String DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT = "4317"; static final Protocol DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = Protocol.GRPC; static final int DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = 10000; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java index 2e8dce776f3..3ac70a21ab0 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java @@ -23,10 +23,6 @@ public final class OtelMetricsConfig { public static final String OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = "otel.exporter.otlp.metrics.temporality.preference"; - public static final String DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX = "v1/metrics"; - public static final String DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT = "4318"; - public static final String DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT = "4317"; - public enum Temporality { CUMULATIVE, DELTA, diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index db3181e93fa..0afb83c4556 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -118,6 +118,9 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRICS_EXPORTER; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_EXPORT_INTERVAL; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT; import static datadog.trace.api.ConfigDefaults.DEFAULT_PARTIAL_FLUSH_MIN_SPANS; @@ -454,9 +457,6 @@ import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_PROTOCOL; import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_TIMEOUT; import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRICS_EXPORTER; -import static datadog.trace.api.config.OtelMetricsConfig.DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT; -import static datadog.trace.api.config.OtelMetricsConfig.DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT; -import static datadog.trace.api.config.OtelMetricsConfig.DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX; import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_INTERVAL; import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_TIMEOUT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS; From 55f786c706deec7806a778062865d9bf3259bbab Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Tue, 4 Nov 2025 22:27:04 +0000 Subject: [PATCH 23/38] Update comment --- .../src/main/java/datadog/trace/api/ConfigDefaults.java | 4 ++-- internal-api/src/main/java/datadog/trace/api/Config.java | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 5109aceb5b8..c4429e6fa56 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -105,9 +105,9 @@ public final class ConfigDefaults { public static final boolean DEFAULT_METRICS_OTEL_ENABLED = false; static final Exporter DEFAULT_OTEL_METRICS_EXPORTER = Exporter.OTLP; - // WARNING: This defies the OpenTelemetry specification’s default value of 60000 (60s) + // Default recommended by Datadog; it differs from Otel’s default of 60000 (60s) static final Integer DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; - // WARNING: This defies the OpenTelemetry specification’s default value of 30000 (30s) + // Default recommended by Datadog; it differs from Otel’s default of 30000 (30s) static final Integer DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT = 7500; static final String DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX = "v1/metrics"; static final String DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT = "4318"; diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 0afb83c4556..7b97ce0af90 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -1914,9 +1914,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins "_"); } otelExporterOtlpMetricsProtocol = tmpOtelExporterOtlpMetricsProtocol; - // TO DO - // Add some error log and switch the protocol to the default value if we don't support the - // selected protocol + // TODO: log warning and switch protocol to default if we don't support the selected protocol? String tmpOtelExporterOtlpMetricsEndpoint = configProvider.getString(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT); From 98ff65eec0dd51aa31beb0f920d6556663e13c7f Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Tue, 4 Nov 2025 22:37:33 +0000 Subject: [PATCH 24/38] Replace concat call with + --- internal-api/src/main/java/datadog/trace/api/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 7b97ce0af90..097c3705969 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -1935,7 +1935,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins } else { tmpOtelExporterOtlpMetricsEndpoint = isHttp - ? tmpOtelExporterOtlpEndpoint.concat(DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX) + ? tmpOtelExporterOtlpEndpoint + DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX : tmpOtelExporterOtlpEndpoint; } } From b10fea324dd6245a673f249d8e352ea1f7b36a37 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 5 Nov 2025 22:25:32 +0000 Subject: [PATCH 25/38] Revert change to ConfigStrings --- .../datadog/trace/util/ConfigStrings.java | 4 ++-- .../trace/api/ConfigStringsTest.groovy | 20 ------------------- 2 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 utils/config-utils/src/test/groovy/datadog/trace/api/ConfigStringsTest.groovy diff --git a/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java b/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java index 11c508ac80a..137280ad539 100644 --- a/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java +++ b/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java @@ -23,7 +23,7 @@ public static String toEnvVarLowerCase(String string) { */ @Nonnull public static String propertyNameToEnvironmentVariableName(final String setting) { - return setting.startsWith("otel.") ? toEnvVar(setting) : "DD_" + toEnvVar(setting); + return "DD_" + toEnvVar(setting); } /** @@ -47,7 +47,7 @@ public static String systemPropertyNameToEnvironmentVariableName(final String se */ @Nonnull public static String propertyNameToSystemPropertyName(final String setting) { - return setting.startsWith("otel.") ? setting : "dd." + setting; + return "dd." + setting; } @Nonnull diff --git a/utils/config-utils/src/test/groovy/datadog/trace/api/ConfigStringsTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/api/ConfigStringsTest.groovy deleted file mode 100644 index 6a52eabe1a0..00000000000 --- a/utils/config-utils/src/test/groovy/datadog/trace/api/ConfigStringsTest.groovy +++ /dev/null @@ -1,20 +0,0 @@ -package datadog.trace.api - -import datadog.trace.test.util.DDSpecification -import datadog.trace.util.ConfigStrings - -class ConfigStringsTest extends DDSpecification { - - - def "test EnvironmentVariable from propertyName"() { - expect: - "DD_FOO_BAR_QUX" == ConfigStrings.propertyNameToEnvironmentVariableName("foo.bar-qux") - "OTEL_BAR_QUX" == ConfigStrings.propertyNameToEnvironmentVariableName("otel.bar-qux") - } - - def "test SystemPropertyName from propertyName"() { - expect: - "dd.foo.bar-qux" == ConfigStrings.propertyNameToSystemPropertyName("foo.bar-qux") - "otel.bar-qux" == ConfigStrings.propertyNameToSystemPropertyName("otel.bar-qux") - } -} From b39223627b98af154bf6cb4d7b3b77dfa0be9c50 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 5 Nov 2025 22:39:46 +0000 Subject: [PATCH 26/38] Rename OtelMetricsConfig to OtlpConfig and drop Exporter enum as it doesn't add value --- ...veImageGeneratorRunnerInstrumentation.java | 5 +- dd-trace-api/build.gradle.kts | 5 +- .../datadog/trace/api/ConfigDefaults.java | 4 +- ...OtelMetricsConfig.java => OtlpConfig.java} | 22 +++--- .../main/java/datadog/trace/api/Config.java | 67 +++++++------------ .../datadog/trace/api/ConfigTest.groovy | 42 +++++------- .../provider/OtelEnvironmentConfigSource.java | 2 +- 7 files changed, 55 insertions(+), 92 deletions(-) rename dd-trace-api/src/main/java/datadog/trace/api/config/{OtelMetricsConfig.java => OtlpConfig.java} (87%) diff --git a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java index 97ffd32f4d6..904a1260842 100644 --- a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java +++ b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java @@ -84,9 +84,8 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[ + "datadog.trace.api.ConfigDefaults:build_time," + "datadog.trace.api.ConfigOrigin:build_time," + "datadog.trace.api.ConfigSetting:build_time," - + "datadog.trace.api.config.OtelMetricsConfig$Exporter:build_time," - + "datadog.trace.api.config.OtelMetricsConfig$Protocol:build_time," - + "datadog.trace.api.config.OtelMetricsConfig$Temporality:build_time," + + "datadog.trace.api.config.OtlpConfig$Protocol:build_time," + + "datadog.trace.api.config.OtlpConfig$Temporality:build_time," + "datadog.trace.api.EventTracker:build_time," + "datadog.trace.api.InstrumenterConfig:build_time," + "datadog.trace.api.Functions:build_time," diff --git a/dd-trace-api/build.gradle.kts b/dd-trace-api/build.gradle.kts index e0042270947..43637568c03 100644 --- a/dd-trace-api/build.gradle.kts +++ b/dd-trace-api/build.gradle.kts @@ -63,9 +63,8 @@ val excludedClassesCoverage by extra( "datadog.trace.payloadtags.PayloadTagsData", "datadog.trace.payloadtags.PayloadTagsData.PathAndValue", "datadog.trace.api.llmobs.LLMObsTags", - "datadog.trace.api.config.OtelMetricsConfig.Protocol", - "datadog.trace.api.config.OtelMetricsConfig.Temporality", - "datadog.trace.api.config.OtelMetricsConfig.Exporter", + "datadog.trace.api.config.OtlpConfig.Protocol", + "datadog.trace.api.config.OtlpConfig.Temporality", ) ) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index c4429e6fa56..736867db990 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -5,8 +5,7 @@ import static datadog.trace.api.TracePropagationStyle.TRACECONTEXT; import static java.util.Arrays.asList; -import datadog.trace.api.config.OtelMetricsConfig.Exporter; -import datadog.trace.api.config.OtelMetricsConfig.Protocol; +import datadog.trace.api.config.OtlpConfig.Protocol; import java.util.Arrays; import java.util.BitSet; import java.util.HashSet; @@ -104,7 +103,6 @@ public final class ConfigDefaults { static final int DEFAULT_JMX_FETCH_MULTIPLE_RUNTIME_SERVICES_LIMIT = 10; public static final boolean DEFAULT_METRICS_OTEL_ENABLED = false; - static final Exporter DEFAULT_OTEL_METRICS_EXPORTER = Exporter.OTLP; // Default recommended by Datadog; it differs from Otel’s default of 60000 (60s) static final Integer DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; // Default recommended by Datadog; it differs from Otel’s default of 30000 (30s) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java similarity index 87% rename from dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java rename to dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java index 3ac70a21ab0..c0f7197975b 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/OtelMetricsConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java @@ -1,10 +1,9 @@ package datadog.trace.api.config; -public final class OtelMetricsConfig { +public final class OtlpConfig { public static final String METRICS_OTEL_ENABLED = "metrics.otel.enabled"; - public static final String OTEL_METRICS_EXPORTER = "otel.metrics.exporter"; public static final String OTEL_METRIC_EXPORT_INTERVAL = "otel.metric.export.interval"; public static final String OTEL_METRIC_EXPORT_TIMEOUT = "otel.metric.export.timeout"; @@ -23,22 +22,17 @@ public final class OtelMetricsConfig { public static final String OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = "otel.exporter.otlp.metrics.temporality.preference"; - public enum Temporality { - CUMULATIVE, - DELTA, - LOWMEMORY - } - - public enum Exporter { - OTLP, - NONE - } - public enum Protocol { GRPC, HTTP_PROTOBUF, HTTP_JSON } - private OtelMetricsConfig() {} + public enum Temporality { + CUMULATIVE, + DELTA, + LOWMEMORY + } + + private OtlpConfig() {} } diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 097c3705969..3aa9d44d585 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -117,7 +117,6 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; -import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRICS_EXPORTER; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX; @@ -446,19 +445,18 @@ import static datadog.trace.api.config.JmxFetchConfig.JMX_TAGS; import static datadog.trace.api.config.LlmObsConfig.LLMOBS_AGENTLESS_ENABLED; import static datadog.trace.api.config.LlmObsConfig.LLMOBS_ML_APP; -import static datadog.trace.api.config.OtelMetricsConfig.METRICS_OTEL_ENABLED; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_ENDPOINT; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_HEADERS; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_PROTOCOL; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_TIMEOUT; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRICS_EXPORTER; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_INTERVAL; -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_TIMEOUT; +import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED; +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_ENDPOINT; +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_HEADERS; +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT; +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS; +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE; +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_PROTOCOL; +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_TIMEOUT; +import static datadog.trace.api.config.OtlpConfig.OTEL_METRIC_EXPORT_INTERVAL; +import static datadog.trace.api.config.OtlpConfig.OTEL_METRIC_EXPORT_TIMEOUT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_API_KEY_FILE_OLD; @@ -687,7 +685,7 @@ import datadog.environment.SystemProperties; import datadog.trace.api.civisibility.CiVisibilityWellKnownTags; import datadog.trace.api.config.GeneralConfig; -import datadog.trace.api.config.OtelMetricsConfig; +import datadog.trace.api.config.OtlpConfig; import datadog.trace.api.config.ProfilingConfig; import datadog.trace.api.config.TracerConfig; import datadog.trace.api.iast.IastContext; @@ -913,14 +911,13 @@ public static String getHostName() { private final int jmxFetchMultipleRuntimeServicesLimit; private final boolean metricsOtelEnabled; - private final OtelMetricsConfig.Exporter otelMetricsExporter; private final Integer otelMetricExportInterval; private final Integer otelMetricExportTimeout; private final String otelExporterOtlpMetricsEndpoint; private final Map otelExporterOtlpMetricsHeaders; - private final OtelMetricsConfig.Protocol otelExporterOtlpMetricsProtocol; + private final OtlpConfig.Protocol otelExporterOtlpMetricsProtocol; private final Integer otelExporterOtlpMetricsTimeout; - private final OtelMetricsConfig.Temporality otelExporterOtlpMetricsTemporalityPreference; + private final OtlpConfig.Temporality otelExporterOtlpMetricsTemporalityPreference; // These values are default-ed to those of jmx fetch values as needed private final boolean healthMetricsEnabled; @@ -1868,13 +1865,6 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins metricsOtelEnabled = configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED); - otelMetricsExporter = - configProvider.getEnum( - OTEL_METRICS_EXPORTER, - OtelMetricsConfig.Exporter.class, - DEFAULT_OTEL_METRICS_EXPORTER, - false); - Integer tmpOtelMetricExportTimeout = configProvider.getInteger(OTEL_METRIC_EXPORT_TIMEOUT); otelMetricExportTimeout = (tmpOtelMetricExportTimeout == null || tmpOtelMetricExportTimeout < 0) @@ -1895,19 +1885,14 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins } otelExporterOtlpMetricsHeaders = tmpOtelExporterOtlpMetricsHeaders; - OtelMetricsConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = + OtlpConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( - OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, - OtelMetricsConfig.Protocol.class, - null, - false, - "/", - "_"); + OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OtlpConfig.Protocol.class, null, false, "/", "_"); if (tmpOtelExporterOtlpMetricsProtocol == null) { tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( OTEL_EXPORTER_OTLP_PROTOCOL, - OtelMetricsConfig.Protocol.class, + OtlpConfig.Protocol.class, DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, false, "/", @@ -1919,7 +1904,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins String tmpOtelExporterOtlpMetricsEndpoint = configProvider.getString(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT); if (tmpOtelExporterOtlpMetricsEndpoint == null) { - boolean isHttp = !otelExporterOtlpMetricsProtocol.equals(OtelMetricsConfig.Protocol.GRPC); + boolean isHttp = !otelExporterOtlpMetricsProtocol.equals(OtlpConfig.Protocol.GRPC); String tmpOtelExporterOtlpEndpoint = configProvider.getString(OTEL_EXPORTER_OTLP_ENDPOINT); if (null == tmpOtelExporterOtlpEndpoint) { String endpointHost = agentHost.isEmpty() ? DEFAULT_AGENT_HOST : agentHost; @@ -1954,8 +1939,8 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins otelExporterOtlpMetricsTemporalityPreference = configProvider.getEnum( OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, - OtelMetricsConfig.Temporality.class, - OtelMetricsConfig.Temporality.DELTA, + OtlpConfig.Temporality.class, + OtlpConfig.Temporality.DELTA, false); // Runtime metrics are disabled if Otel metrics are enabled and the metrics exporter is none @@ -5101,10 +5086,6 @@ public boolean isMetricsOtelEnabled() { return metricsOtelEnabled; } - public OtelMetricsConfig.Exporter getOtelMetricsExporter() { - return otelMetricsExporter; - } - public Integer getOtelMetricExportInterval() { return otelMetricExportInterval; } @@ -5121,7 +5102,7 @@ public Map getOtelExporterOtlpMetricsHeaders() { return otelExporterOtlpMetricsHeaders; } - public OtelMetricsConfig.Protocol getOtelExporterOtlpMetricsProtocol() { + public OtlpConfig.Protocol getOtelExporterOtlpMetricsProtocol() { return otelExporterOtlpMetricsProtocol; } @@ -5129,7 +5110,7 @@ public Integer getOtelExporterOtlpMetricsTimeout() { return otelExporterOtlpMetricsTimeout; } - public OtelMetricsConfig.Temporality getOtelExporterOtlpMetricsTemporalityPreference() { + public OtlpConfig.Temporality getOtelExporterOtlpMetricsTemporalityPreference() { return otelExporterOtlpMetricsTemporalityPreference; } @@ -6123,8 +6104,6 @@ public String toString() { + aiGuardEndpoint + ", metricsOtelEnabled=" + metricsOtelEnabled - + ", otelMetricsExporter=" - + otelMetricsExporter + ", otelMetricExportInterval=" + otelMetricExportInterval + ", otelMetricExportTimeout=" diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index bdb552da0d9..20bb2369509 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -137,25 +137,24 @@ import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_OPERATION_RUL import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_SERVICE_RULES import static datadog.trace.api.config.TracerConfig.TRACE_X_DATADOG_TAGS_MAX_LENGTH import static datadog.trace.api.config.TracerConfig.WRITER_TYPE -import static datadog.trace.api.config.OtelMetricsConfig.Protocol.GRPC -import static datadog.trace.api.config.OtelMetricsConfig.Protocol.HTTP_PROTOBUF -import static datadog.trace.api.config.OtelMetricsConfig.Protocol.HTTP_JSON -import static datadog.trace.api.config.OtelMetricsConfig.Exporter.OTLP -import static datadog.trace.api.config.OtelMetricsConfig.Temporality.CUMULATIVE -import static datadog.trace.api.config.OtelMetricsConfig.Temporality.DELTA -import static datadog.trace.api.config.OtelMetricsConfig.METRICS_OTEL_ENABLED -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_ENDPOINT -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRICS_EXPORTER -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_INTERVAL -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_METRIC_EXPORT_TIMEOUT -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_PROTOCOL -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_TIMEOUT -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_HEADERS -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT -import static datadog.trace.api.config.OtelMetricsConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE +import static datadog.trace.api.config.OtlpConfig.Protocol.GRPC +import static datadog.trace.api.config.OtlpConfig.Protocol.HTTP_PROTOBUF +import static datadog.trace.api.config.OtlpConfig.Protocol.HTTP_JSON +import static datadog.trace.api.config.OtlpConfig.Temporality.CUMULATIVE +import static datadog.trace.api.config.OtlpConfig.Temporality.DELTA +import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_ENDPOINT +import static datadog.trace.api.config.OtlpConfig.OTEL_METRICS_EXPORTER +import static datadog.trace.api.config.OtlpConfig.OTEL_METRIC_EXPORT_INTERVAL +import static datadog.trace.api.config.OtlpConfig.OTEL_METRIC_EXPORT_TIMEOUT +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_PROTOCOL +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_TIMEOUT +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_HEADERS +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT +import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE import datadog.trace.config.inversion.ConfigHelper class ConfigTest extends DDSpecification { @@ -410,7 +409,6 @@ class ConfigTest extends DDSpecification { config.jdkSocketEnabled == false config.metricsOtelEnabled - config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 11000 config.otelMetricExportTimeout == 9000 config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" @@ -441,7 +439,6 @@ class ConfigTest extends DDSpecification { then: !config.metricsOtelEnabled - config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 10000 config.otelMetricExportTimeout == 7500 config.otelExporterOtlpMetricsEndpoint == "invalid" @@ -460,7 +457,6 @@ class ConfigTest extends DDSpecification { then: !config.metricsOtelEnabled - config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 10000 config.otelMetricExportTimeout == 7500 config.otelExporterOtlpMetricsEndpoint == "http://localhost:4317" @@ -810,7 +806,6 @@ class ConfigTest extends DDSpecification { config.metricsOtelEnabled config.version == "1.0.0" config.env == "production" - config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 11000 config.otelMetricExportTimeout == 9000 config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" @@ -869,7 +864,6 @@ class ConfigTest extends DDSpecification { config.requestHeaderTags == ["*":"http.request.headers."] config.responseHeaderTags == ["*":"http.response.headers."] config.metricsOtelEnabled - config.otelMetricsExporter == OTLP config.otelMetricExportInterval == 11000 config.otelMetricExportTimeout == 9000 config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java index 00c61666784..c6169be323b 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java @@ -8,7 +8,7 @@ import static datadog.trace.api.config.GeneralConfig.SERVICE_NAME; import static datadog.trace.api.config.GeneralConfig.TAGS; import static datadog.trace.api.config.GeneralConfig.VERSION; -import static datadog.trace.api.config.OtelMetricsConfig.METRICS_OTEL_ENABLED; +import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_ENABLED; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_EXTENSIONS_PATH; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_OTEL_ENABLED; From 4c2385b71164824ca49749340d77da77576a57d3 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 5 Nov 2025 22:54:17 +0000 Subject: [PATCH 27/38] Make ConfigProvider.getEnum more robust: make value uppercase and replace known bad characters before converting --- .../main/java/datadog/trace/api/Config.java | 10 +++----- .../config/provider/ConfigProvider.java | 23 +++---------------- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 3aa9d44d585..06e25704fca 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -1887,16 +1887,13 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins OtlpConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( - OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OtlpConfig.Protocol.class, null, false, "/", "_"); + OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OtlpConfig.Protocol.class, null); if (tmpOtelExporterOtlpMetricsProtocol == null) { tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( OTEL_EXPORTER_OTLP_PROTOCOL, OtlpConfig.Protocol.class, - DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, - false, - "/", - "_"); + DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL); } otelExporterOtlpMetricsProtocol = tmpOtelExporterOtlpMetricsProtocol; // TODO: log warning and switch protocol to default if we don't support the selected protocol? @@ -1940,8 +1937,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins configProvider.getEnum( OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, OtlpConfig.Temporality.class, - OtlpConfig.Temporality.DELTA, - false); + OtlpConfig.Temporality.DELTA); // Runtime metrics are disabled if Otel metrics are enabled and the metrics exporter is none runtimeMetricsEnabled = configProvider.getBoolean(RUNTIME_METRICS_ENABLED, true); diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java index 21d9949ae8c..ea8172ce66d 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java @@ -21,6 +21,7 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Properties; @@ -104,21 +105,6 @@ private String getStringInternal(String key, String... aliases) { } public > T getEnum(String key, Class enumType, T defaultValue) { - return getEnum(key, enumType, defaultValue, true); - } - - public > T getEnum( - String key, Class enumType, T defaultValue, boolean isValueCaseSensitive) { - return getEnum(key, enumType, defaultValue, isValueCaseSensitive, "", ""); - } - - public > T getEnum( - String key, - Class enumType, - T defaultValue, - boolean isValueCaseSensitive, - String charToReplaceInRawValue, - String newCharInValue) { if (collectConfig) { String defaultValueString = defaultValue == null ? null : defaultValue.name(); reportDefault(key, defaultValueString); @@ -126,11 +112,8 @@ public > T getEnum( String value = getStringInternal(key); if (null != value) { try { - return Enum.valueOf( - enumType, - isValueCaseSensitive - ? value.replace(charToReplaceInRawValue, newCharInValue) - : value.toUpperCase().replace(charToReplaceInRawValue, newCharInValue)); + // replace invalid characters with _ and make sure it's upper-case before converting + return Enum.valueOf(enumType, value.replace('/', '_').toUpperCase(Locale.ROOT)); } catch (Exception ignoreAndUseDefault) { log.debug("failed to parse {} for {}, defaulting to {}", value, key, defaultValue); } From 71600b19822c87fd8da40aa2a7b872bfec158d7c Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 5 Nov 2025 23:07:10 +0000 Subject: [PATCH 28/38] Cleanup ConfigDefaults --- .../datadog/trace/api/ConfigDefaults.java | 14 ++++---- .../main/java/datadog/trace/api/Config.java | 32 +++++++++---------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 736867db990..6205504fd1c 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -5,7 +5,6 @@ import static datadog.trace.api.TracePropagationStyle.TRACECONTEXT; import static java.util.Arrays.asList; -import datadog.trace.api.config.OtlpConfig.Protocol; import java.util.Arrays; import java.util.BitSet; import java.util.HashSet; @@ -104,14 +103,13 @@ public final class ConfigDefaults { public static final boolean DEFAULT_METRICS_OTEL_ENABLED = false; // Default recommended by Datadog; it differs from Otel’s default of 60000 (60s) - static final Integer DEFAULT_OTEL_METRIC_EXPORT_INTERVAL = 10000; + static final int DEFAULT_METRICS_OTEL_INTERVAL = 10000; // ms // Default recommended by Datadog; it differs from Otel’s default of 30000 (30s) - static final Integer DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT = 7500; - static final String DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX = "v1/metrics"; - static final String DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT = "4318"; - static final String DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT = "4317"; - static final Protocol DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = Protocol.GRPC; - static final int DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = 10000; + static final int DEFAULT_METRICS_OTEL_TIMEOUT = 7500; // ms + + static final String DEFAULT_OTLP_HTTP_METRIC_ENDPOINT = "v1/metrics"; + static final String DEFAULT_OTLP_HTTP_PORT = "4318"; + static final String DEFAULT_OTLP_GRPC_PORT = "4317"; static final int DEFAULT_DOGSTATSD_START_DELAY = 15; // seconds diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 06e25704fca..09242e4d338 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -115,13 +115,11 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_LLM_OBS_AGENTLESS_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_LOGS_INJECTION_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_ENABLED; -import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; -import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; -import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT; -import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT; -import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX; -import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_EXPORT_INTERVAL; -import static datadog.trace.api.ConfigDefaults.DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_INTERVAL; +import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_TIMEOUT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTLP_GRPC_PORT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTLP_HTTP_METRIC_ENDPOINT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTLP_HTTP_PORT; import static datadog.trace.api.ConfigDefaults.DEFAULT_PARTIAL_FLUSH_MIN_SPANS; import static datadog.trace.api.ConfigDefaults.DEFAULT_PERF_METRICS_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_PRIORITY_SAMPLING_ENABLED; @@ -1868,13 +1866,13 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins Integer tmpOtelMetricExportTimeout = configProvider.getInteger(OTEL_METRIC_EXPORT_TIMEOUT); otelMetricExportTimeout = (tmpOtelMetricExportTimeout == null || tmpOtelMetricExportTimeout < 0) - ? DEFAULT_OTEL_METRIC_EXPORT_TIMEOUT + ? DEFAULT_METRICS_OTEL_TIMEOUT : tmpOtelMetricExportTimeout; Integer tmpOtelMetricExportInterval = configProvider.getInteger(OTEL_METRIC_EXPORT_INTERVAL); otelMetricExportInterval = (tmpOtelMetricExportInterval == null || tmpOtelMetricExportInterval < 0) - ? DEFAULT_OTEL_METRIC_EXPORT_INTERVAL + ? DEFAULT_METRICS_OTEL_INTERVAL : tmpOtelMetricExportInterval; Map tmpOtelExporterOtlpMetricsHeaders = @@ -1893,7 +1891,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins configProvider.getEnum( OTEL_EXPORTER_OTLP_PROTOCOL, OtlpConfig.Protocol.class, - DEFAULT_OTEL_EXPORTER_OTLP_METRICS_PROTOCOL); + OtlpConfig.Protocol.HTTP_PROTOBUF); } otelExporterOtlpMetricsProtocol = tmpOtelExporterOtlpMetricsProtocol; // TODO: log warning and switch protocol to default if we don't support the selected protocol? @@ -1909,15 +1907,15 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins isHttp ? "http://" + endpointHost - + ":" - + DEFAULT_OTEL_METRIC_ENDPOINT_HTTP_PORT - + "/" - + DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX - : "http://" + endpointHost + ":" + DEFAULT_OTEL_METRIC_ENDPOINT_GRPC_PORT; + + ':' + + DEFAULT_OTLP_HTTP_PORT + + '/' + + DEFAULT_OTLP_HTTP_METRIC_ENDPOINT + : "http://" + endpointHost + ':' + DEFAULT_OTLP_GRPC_PORT; } else { tmpOtelExporterOtlpMetricsEndpoint = isHttp - ? tmpOtelExporterOtlpEndpoint + DEFAULT_OTEL_METRIC_ENDPOINT_SUFFIX + ? tmpOtelExporterOtlpEndpoint + '/' + DEFAULT_OTLP_HTTP_METRIC_ENDPOINT : tmpOtelExporterOtlpEndpoint; } } @@ -1930,7 +1928,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins } otelExporterOtlpMetricsTimeout = (tmpOtelExporterOtlpMetricsTimeout == null || tmpOtelExporterOtlpMetricsTimeout < 0) - ? new Integer(DEFAULT_OTEL_EXPORTER_OTLP_METRICS_TIMEOUT) + ? Math.min(otelMetricExportTimeout, DEFAULT_METRICS_OTEL_TIMEOUT) : tmpOtelExporterOtlpMetricsTimeout; otelExporterOtlpMetricsTemporalityPreference = From c38ce90f91a3fc6990304c0e79966d71069b1929 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 5 Nov 2025 23:35:45 +0000 Subject: [PATCH 29/38] Ensure agentHost is never empty --- internal-api/src/main/java/datadog/trace/api/Config.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 09242e4d338..f6401e18719 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -1481,7 +1481,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins } } - if (agentHostFromEnvironment == null) { + if (agentHostFromEnvironment == null || agentHostFromEnvironment.isEmpty()) { agentHost = DEFAULT_AGENT_HOST; } else if (agentHostFromEnvironment.charAt(0) == '[') { agentHost = agentHostFromEnvironment.substring(1, agentHostFromEnvironment.length() - 1); @@ -1902,16 +1902,15 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins boolean isHttp = !otelExporterOtlpMetricsProtocol.equals(OtlpConfig.Protocol.GRPC); String tmpOtelExporterOtlpEndpoint = configProvider.getString(OTEL_EXPORTER_OTLP_ENDPOINT); if (null == tmpOtelExporterOtlpEndpoint) { - String endpointHost = agentHost.isEmpty() ? DEFAULT_AGENT_HOST : agentHost; tmpOtelExporterOtlpMetricsEndpoint = isHttp ? "http://" - + endpointHost + + agentHost + ':' + DEFAULT_OTLP_HTTP_PORT + '/' + DEFAULT_OTLP_HTTP_METRIC_ENDPOINT - : "http://" + endpointHost + ':' + DEFAULT_OTLP_GRPC_PORT; + : "http://" + agentHost + ':' + DEFAULT_OTLP_GRPC_PORT; } else { tmpOtelExporterOtlpMetricsEndpoint = isHttp From 16cbde49129c0a35e119d944657e7ae59c4bb16b Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 5 Nov 2025 23:42:39 +0000 Subject: [PATCH 30/38] Cleanup metrics internal config --- .../datadog/trace/api/config/OtlpConfig.java | 5 +-- .../main/java/datadog/trace/api/Config.java | 38 +++++++++---------- .../datadog/trace/api/ConfigTest.groovy | 37 +++++++++--------- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java index c0f7197975b..2fd3c32d771 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java @@ -3,9 +3,8 @@ public final class OtlpConfig { public static final String METRICS_OTEL_ENABLED = "metrics.otel.enabled"; - - public static final String OTEL_METRIC_EXPORT_INTERVAL = "otel.metric.export.interval"; - public static final String OTEL_METRIC_EXPORT_TIMEOUT = "otel.metric.export.timeout"; + public static final String METRICS_OTEL_INTERVAL = "metrics.otel.interval"; + public static final String METRICS_OTEL_TIMEOUT = "metrics.otel.timeout"; public static final String OTEL_EXPORTER_OTLP_ENDPOINT = "otel.exporter.otlp.endpoint"; public static final String OTEL_EXPORTER_OTLP_HEADERS = "otel.exporter.otlp.headers"; diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index f6401e18719..c3babf5df3c 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -444,6 +444,8 @@ import static datadog.trace.api.config.LlmObsConfig.LLMOBS_AGENTLESS_ENABLED; import static datadog.trace.api.config.LlmObsConfig.LLMOBS_ML_APP; import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED; +import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL; +import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT; import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_ENDPOINT; import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_HEADERS; import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT; @@ -453,8 +455,6 @@ import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_PROTOCOL; import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_TIMEOUT; -import static datadog.trace.api.config.OtlpConfig.OTEL_METRIC_EXPORT_INTERVAL; -import static datadog.trace.api.config.OtlpConfig.OTEL_METRIC_EXPORT_TIMEOUT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_API_KEY_FILE_OLD; @@ -909,12 +909,12 @@ public static String getHostName() { private final int jmxFetchMultipleRuntimeServicesLimit; private final boolean metricsOtelEnabled; - private final Integer otelMetricExportInterval; - private final Integer otelMetricExportTimeout; + private final int metricsOtelInterval; + private final int metricsOtelTimeout; private final String otelExporterOtlpMetricsEndpoint; private final Map otelExporterOtlpMetricsHeaders; private final OtlpConfig.Protocol otelExporterOtlpMetricsProtocol; - private final Integer otelExporterOtlpMetricsTimeout; + private final int otelExporterOtlpMetricsTimeout; private final OtlpConfig.Temporality otelExporterOtlpMetricsTemporalityPreference; // These values are default-ed to those of jmx fetch values as needed @@ -1863,14 +1863,14 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins metricsOtelEnabled = configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED); - Integer tmpOtelMetricExportTimeout = configProvider.getInteger(OTEL_METRIC_EXPORT_TIMEOUT); - otelMetricExportTimeout = + Integer tmpOtelMetricExportTimeout = configProvider.getInteger(METRICS_OTEL_TIMEOUT); + metricsOtelTimeout = (tmpOtelMetricExportTimeout == null || tmpOtelMetricExportTimeout < 0) ? DEFAULT_METRICS_OTEL_TIMEOUT : tmpOtelMetricExportTimeout; - Integer tmpOtelMetricExportInterval = configProvider.getInteger(OTEL_METRIC_EXPORT_INTERVAL); - otelMetricExportInterval = + Integer tmpOtelMetricExportInterval = configProvider.getInteger(METRICS_OTEL_INTERVAL); + metricsOtelInterval = (tmpOtelMetricExportInterval == null || tmpOtelMetricExportInterval < 0) ? DEFAULT_METRICS_OTEL_INTERVAL : tmpOtelMetricExportInterval; @@ -1927,7 +1927,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins } otelExporterOtlpMetricsTimeout = (tmpOtelExporterOtlpMetricsTimeout == null || tmpOtelExporterOtlpMetricsTimeout < 0) - ? Math.min(otelMetricExportTimeout, DEFAULT_METRICS_OTEL_TIMEOUT) + ? Math.min(metricsOtelTimeout, DEFAULT_METRICS_OTEL_TIMEOUT) : tmpOtelExporterOtlpMetricsTimeout; otelExporterOtlpMetricsTemporalityPreference = @@ -5079,12 +5079,12 @@ public boolean isMetricsOtelEnabled() { return metricsOtelEnabled; } - public Integer getOtelMetricExportInterval() { - return otelMetricExportInterval; + public int getMetricsOtelInterval() { + return metricsOtelInterval; } - public Integer getOtelMetricExportTimeout() { - return otelMetricExportTimeout; + public int getMetricsOtelTimeout() { + return metricsOtelTimeout; } public String getOtelExporterOtlpMetricsEndpoint() { @@ -5099,7 +5099,7 @@ public OtlpConfig.Protocol getOtelExporterOtlpMetricsProtocol() { return otelExporterOtlpMetricsProtocol; } - public Integer getOtelExporterOtlpMetricsTimeout() { + public int getOtelExporterOtlpMetricsTimeout() { return otelExporterOtlpMetricsTimeout; } @@ -6097,10 +6097,10 @@ public String toString() { + aiGuardEndpoint + ", metricsOtelEnabled=" + metricsOtelEnabled - + ", otelMetricExportInterval=" - + otelMetricExportInterval - + ", otelMetricExportTimeout=" - + otelMetricExportTimeout + + ", metricsOtelInterval=" + + metricsOtelInterval + + ", metricsOtelTimeout=" + + metricsOtelTimeout + ", otelExporterOtlpMetricsEndpoint=" + otelExporterOtlpMetricsEndpoint + ", otelExporterOtlpMetricsHeaders=" diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 20bb2369509..e184a44fed6 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -144,9 +144,8 @@ import static datadog.trace.api.config.OtlpConfig.Temporality.CUMULATIVE import static datadog.trace.api.config.OtlpConfig.Temporality.DELTA import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_ENDPOINT -import static datadog.trace.api.config.OtlpConfig.OTEL_METRICS_EXPORTER -import static datadog.trace.api.config.OtlpConfig.OTEL_METRIC_EXPORT_INTERVAL -import static datadog.trace.api.config.OtlpConfig.OTEL_METRIC_EXPORT_TIMEOUT +import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL +import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_PROTOCOL import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_TIMEOUT import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT @@ -304,8 +303,8 @@ class ConfigTest extends DDSpecification { prop.setProperty(METRICS_OTEL_ENABLED, "True") prop.setProperty(OTEL_METRICS_EXPORTER, "otlp") - prop.setProperty(OTEL_METRIC_EXPORT_INTERVAL, "11000") - prop.setProperty(OTEL_METRIC_EXPORT_TIMEOUT, "9000") + prop.setProperty(METRICS_OTEL_INTERVAL, "11000") + prop.setProperty(METRICS_OTEL_TIMEOUT, "9000") prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "api-key=key,other-config-value=value") prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, "http/protobuf") @@ -409,8 +408,8 @@ class ConfigTest extends DDSpecification { config.jdkSocketEnabled == false config.metricsOtelEnabled - config.otelMetricExportInterval == 11000 - config.otelMetricExportTimeout == 9000 + config.metricsOtelInterval == 11000 + config.metricsOtelTimeout == 9000 config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" config.otelExporterOtlpMetricsHeaders["api-key"] == "key" config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" @@ -426,8 +425,8 @@ class ConfigTest extends DDSpecification { prop.setProperty(METRICS_OTEL_ENABLED, "youhou") prop.setProperty(OTEL_METRICS_EXPORTER, "invalid") - prop.setProperty(OTEL_METRIC_EXPORT_INTERVAL, "-1") - prop.setProperty(OTEL_METRIC_EXPORT_TIMEOUT, "invalid") + prop.setProperty(METRICS_OTEL_INTERVAL, "-1") + prop.setProperty(METRICS_OTEL_TIMEOUT, "invalid") prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, "invalid") prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "11") prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, "invalid") @@ -439,8 +438,8 @@ class ConfigTest extends DDSpecification { then: !config.metricsOtelEnabled - config.otelMetricExportInterval == 10000 - config.otelMetricExportTimeout == 7500 + config.metricsOtelInterval == 10000 + config.metricsOtelTimeout == 7500 config.otelExporterOtlpMetricsEndpoint == "invalid" config.otelExporterOtlpMetricsHeaders == [:] config.otelExporterOtlpMetricsProtocol == GRPC @@ -457,8 +456,8 @@ class ConfigTest extends DDSpecification { then: !config.metricsOtelEnabled - config.otelMetricExportInterval == 10000 - config.otelMetricExportTimeout == 7500 + config.metricsOtelInterval == 10000 + config.metricsOtelTimeout == 7500 config.otelExporterOtlpMetricsEndpoint == "http://localhost:4317" config.otelExporterOtlpMetricsHeaders == [:] config.otelExporterOtlpMetricsProtocol == GRPC @@ -702,8 +701,8 @@ class ConfigTest extends DDSpecification { System.setProperty(PREFIX + METRICS_OTEL_ENABLED, "True") System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production") System.setProperty(OTEL_METRICS_EXPORTER, "otlp") - System.setProperty(OTEL_METRIC_EXPORT_INTERVAL, "11000") - System.setProperty(OTEL_METRIC_EXPORT_TIMEOUT, "9000") + System.setProperty(METRICS_OTEL_INTERVAL, "11000") + System.setProperty(METRICS_OTEL_TIMEOUT, "9000") System.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") System.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "api-key=key,other-config-value=value") System.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, "http/protobuf") @@ -806,8 +805,8 @@ class ConfigTest extends DDSpecification { config.metricsOtelEnabled config.version == "1.0.0" config.env == "production" - config.otelMetricExportInterval == 11000 - config.otelMetricExportTimeout == 9000 + config.metricsOtelInterval == 11000 + config.metricsOtelTimeout == 9000 config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" config.otelExporterOtlpMetricsHeaders["api-key"] == "key" config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" @@ -864,8 +863,8 @@ class ConfigTest extends DDSpecification { config.requestHeaderTags == ["*":"http.request.headers."] config.responseHeaderTags == ["*":"http.response.headers."] config.metricsOtelEnabled - config.otelMetricExportInterval == 11000 - config.otelMetricExportTimeout == 9000 + config.metricsOtelInterval == 11000 + config.metricsOtelTimeout == 9000 config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" config.otelExporterOtlpMetricsHeaders["api-key"] == "key" config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" From a0a62b59c253e76fc3663f5085b5c0a97de69d38 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 5 Nov 2025 23:47:22 +0000 Subject: [PATCH 31/38] Remove static import --- internal-api/src/main/java/datadog/trace/api/Config.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index c3babf5df3c..25cd3cbc766 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -672,7 +672,6 @@ import static datadog.trace.api.config.TracerConfig.TRACE_X_DATADOG_TAGS_MAX_LENGTH; import static datadog.trace.api.config.TracerConfig.WRITER_BAGGAGE_INJECT; import static datadog.trace.api.config.TracerConfig.WRITER_TYPE; -import static datadog.trace.api.iast.IastDetectionMode.DEFAULT; import static datadog.trace.api.telemetry.LogCollector.SEND_TELEMETRY; import static datadog.trace.util.CollectionUtils.tryMakeImmutableList; import static datadog.trace.util.CollectionUtils.tryMakeImmutableSet; @@ -2261,7 +2260,8 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) iastContextMode = configProvider.getEnum(IAST_CONTEXT_MODE, IastContext.Mode.class, IastContext.Mode.REQUEST); iastDetectionMode = - configProvider.getEnum(IAST_DETECTION_MODE, IastDetectionMode.class, DEFAULT); + configProvider.getEnum( + IAST_DETECTION_MODE, IastDetectionMode.class, IastDetectionMode.DEFAULT); iastMaxConcurrentRequests = iastDetectionMode.getIastMaxConcurrentRequests(configProvider); iastVulnerabilitiesPerRequest = iastDetectionMode.getIastVulnerabilitiesPerRequest(configProvider); From 7e4a11f91e0275f802deffc2239fd2b36cef0483 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 5 Nov 2025 23:53:53 +0000 Subject: [PATCH 32/38] Cleanup metrics internal OTLP config --- .../datadog/trace/api/config/OtlpConfig.java | 25 ++-- .../main/java/datadog/trace/api/Config.java | 104 +++++++------- .../datadog/trace/api/ConfigTest.groovy | 135 +++++++++--------- 3 files changed, 127 insertions(+), 137 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java index 2fd3c32d771..29cc7a8241a 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java @@ -6,20 +6,17 @@ public final class OtlpConfig { public static final String METRICS_OTEL_INTERVAL = "metrics.otel.interval"; public static final String METRICS_OTEL_TIMEOUT = "metrics.otel.timeout"; - public static final String OTEL_EXPORTER_OTLP_ENDPOINT = "otel.exporter.otlp.endpoint"; - public static final String OTEL_EXPORTER_OTLP_HEADERS = "otel.exporter.otlp.headers"; - public static final String OTEL_EXPORTER_OTLP_PROTOCOL = "otel.exporter.otlp.protocol"; - public static final String OTEL_EXPORTER_OTLP_TIMEOUT = "otel.exporter.otlp.timeout"; - public static final String OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = - "otel.exporter.otlp.metrics.endpoint"; - public static final String OTEL_EXPORTER_OTLP_METRICS_HEADERS = - "otel.exporter.otlp.metrics.headers"; - public static final String OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = - "otel.exporter.otlp.metrics.protocol"; - public static final String OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = - "otel.exporter.otlp.metrics.timeout"; - public static final String OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = - "otel.exporter.otlp.metrics.temporality.preference"; + public static final String OTLP_ENDPOINT = "otlp.endpoint"; + public static final String OTLP_HEADERS = "otlp.headers"; + public static final String OTLP_PROTOCOL = "otlp.protocol"; + public static final String OTLP_TIMEOUT = "otlp.timeout"; + + public static final String OTLP_METRICS_ENDPOINT = "otlp.metrics.endpoint"; + public static final String OTLP_METRICS_HEADERS = "otlp.metrics.headers"; + public static final String OTLP_METRICS_PROTOCOL = "otlp.metrics.protocol"; + public static final String OTLP_METRICS_TIMEOUT = "otlp.metrics.timeout"; + public static final String OTLP_METRICS_TEMPORALITY_PREFERENCE = + "otlp.metrics.temporality.preference"; public enum Protocol { GRPC, diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 25cd3cbc766..f2906a44c76 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -446,15 +446,15 @@ import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED; import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL; import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT; -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_ENDPOINT; -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_HEADERS; -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT; -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS; -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL; -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE; -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT; -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_PROTOCOL; -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_TIMEOUT; +import static datadog.trace.api.config.OtlpConfig.OTLP_ENDPOINT; +import static datadog.trace.api.config.OtlpConfig.OTLP_HEADERS; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_ENDPOINT; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_HEADERS; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_PROTOCOL; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TEMPORALITY_PREFERENCE; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TIMEOUT; +import static datadog.trace.api.config.OtlpConfig.OTLP_PROTOCOL; +import static datadog.trace.api.config.OtlpConfig.OTLP_TIMEOUT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_API_KEY_FILE_OLD; @@ -910,11 +910,11 @@ public static String getHostName() { private final boolean metricsOtelEnabled; private final int metricsOtelInterval; private final int metricsOtelTimeout; - private final String otelExporterOtlpMetricsEndpoint; - private final Map otelExporterOtlpMetricsHeaders; - private final OtlpConfig.Protocol otelExporterOtlpMetricsProtocol; - private final int otelExporterOtlpMetricsTimeout; - private final OtlpConfig.Temporality otelExporterOtlpMetricsTemporalityPreference; + private final String otlpMetricsEndpoint; + private final Map otlpMetricsHeaders; + private final OtlpConfig.Protocol otlpMetricsProtocol; + private final int otlpMetricsTimeout; + private final OtlpConfig.Temporality otlpMetricsTemporalityPreference; // These values are default-ed to those of jmx fetch values as needed private final boolean healthMetricsEnabled; @@ -1875,31 +1875,26 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins : tmpOtelMetricExportInterval; Map tmpOtelExporterOtlpMetricsHeaders = - configProvider.getMergedMap(OTEL_EXPORTER_OTLP_METRICS_HEADERS, '='); + configProvider.getMergedMap(OTLP_METRICS_HEADERS, '='); if (tmpOtelExporterOtlpMetricsHeaders.isEmpty()) { - tmpOtelExporterOtlpMetricsHeaders = - configProvider.getMergedMap(OTEL_EXPORTER_OTLP_HEADERS, '='); + tmpOtelExporterOtlpMetricsHeaders = configProvider.getMergedMap(OTLP_HEADERS, '='); } - otelExporterOtlpMetricsHeaders = tmpOtelExporterOtlpMetricsHeaders; + otlpMetricsHeaders = tmpOtelExporterOtlpMetricsHeaders; OtlpConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = - configProvider.getEnum( - OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OtlpConfig.Protocol.class, null); + configProvider.getEnum(OTLP_METRICS_PROTOCOL, OtlpConfig.Protocol.class, null); if (tmpOtelExporterOtlpMetricsProtocol == null) { tmpOtelExporterOtlpMetricsProtocol = configProvider.getEnum( - OTEL_EXPORTER_OTLP_PROTOCOL, - OtlpConfig.Protocol.class, - OtlpConfig.Protocol.HTTP_PROTOBUF); + OTLP_PROTOCOL, OtlpConfig.Protocol.class, OtlpConfig.Protocol.HTTP_PROTOBUF); } - otelExporterOtlpMetricsProtocol = tmpOtelExporterOtlpMetricsProtocol; + otlpMetricsProtocol = tmpOtelExporterOtlpMetricsProtocol; // TODO: log warning and switch protocol to default if we don't support the selected protocol? - String tmpOtelExporterOtlpMetricsEndpoint = - configProvider.getString(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT); + String tmpOtelExporterOtlpMetricsEndpoint = configProvider.getString(OTLP_METRICS_ENDPOINT); if (tmpOtelExporterOtlpMetricsEndpoint == null) { - boolean isHttp = !otelExporterOtlpMetricsProtocol.equals(OtlpConfig.Protocol.GRPC); - String tmpOtelExporterOtlpEndpoint = configProvider.getString(OTEL_EXPORTER_OTLP_ENDPOINT); + boolean isHttp = !otlpMetricsProtocol.equals(OtlpConfig.Protocol.GRPC); + String tmpOtelExporterOtlpEndpoint = configProvider.getString(OTLP_ENDPOINT); if (null == tmpOtelExporterOtlpEndpoint) { tmpOtelExporterOtlpMetricsEndpoint = isHttp @@ -1917,21 +1912,20 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins : tmpOtelExporterOtlpEndpoint; } } - otelExporterOtlpMetricsEndpoint = tmpOtelExporterOtlpMetricsEndpoint; + otlpMetricsEndpoint = tmpOtelExporterOtlpMetricsEndpoint; - Integer tmpOtelExporterOtlpMetricsTimeout = - configProvider.getInteger(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT); + Integer tmpOtelExporterOtlpMetricsTimeout = configProvider.getInteger(OTLP_METRICS_TIMEOUT); if (null == tmpOtelExporterOtlpMetricsTimeout) { - tmpOtelExporterOtlpMetricsTimeout = configProvider.getInteger(OTEL_EXPORTER_OTLP_TIMEOUT); + tmpOtelExporterOtlpMetricsTimeout = configProvider.getInteger(OTLP_TIMEOUT); } - otelExporterOtlpMetricsTimeout = + otlpMetricsTimeout = (tmpOtelExporterOtlpMetricsTimeout == null || tmpOtelExporterOtlpMetricsTimeout < 0) ? Math.min(metricsOtelTimeout, DEFAULT_METRICS_OTEL_TIMEOUT) : tmpOtelExporterOtlpMetricsTimeout; - otelExporterOtlpMetricsTemporalityPreference = + otlpMetricsTemporalityPreference = configProvider.getEnum( - OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, + OTLP_METRICS_TEMPORALITY_PREFERENCE, OtlpConfig.Temporality.class, OtlpConfig.Temporality.DELTA); @@ -5087,24 +5081,24 @@ public int getMetricsOtelTimeout() { return metricsOtelTimeout; } - public String getOtelExporterOtlpMetricsEndpoint() { - return otelExporterOtlpMetricsEndpoint; + public String getOtlpMetricsEndpoint() { + return otlpMetricsEndpoint; } - public Map getOtelExporterOtlpMetricsHeaders() { - return otelExporterOtlpMetricsHeaders; + public Map getOtlpMetricsHeaders() { + return otlpMetricsHeaders; } - public OtlpConfig.Protocol getOtelExporterOtlpMetricsProtocol() { - return otelExporterOtlpMetricsProtocol; + public OtlpConfig.Protocol getOtlpMetricsProtocol() { + return otlpMetricsProtocol; } - public int getOtelExporterOtlpMetricsTimeout() { - return otelExporterOtlpMetricsTimeout; + public int getOtlpMetricsTimeout() { + return otlpMetricsTimeout; } - public OtlpConfig.Temporality getOtelExporterOtlpMetricsTemporalityPreference() { - return otelExporterOtlpMetricsTemporalityPreference; + public OtlpConfig.Temporality getOtlpMetricsTemporalityPreference() { + return otlpMetricsTemporalityPreference; } public boolean isRuleEnabled(final String name) { @@ -6101,16 +6095,16 @@ public String toString() { + metricsOtelInterval + ", metricsOtelTimeout=" + metricsOtelTimeout - + ", otelExporterOtlpMetricsEndpoint=" - + otelExporterOtlpMetricsEndpoint - + ", otelExporterOtlpMetricsHeaders=" - + otelExporterOtlpMetricsHeaders - + ", otelExporterOtlpMetricsProtocol=" - + otelExporterOtlpMetricsProtocol - + ", otelExporterOtlpMetricsTimeout=" - + otelExporterOtlpMetricsTimeout - + ", otelExporterOtlpMetricsTemporalityPreference=" - + otelExporterOtlpMetricsTemporalityPreference + + ", otlpMetricsEndpoint=" + + otlpMetricsEndpoint + + ", otlpMetricsHeaders=" + + otlpMetricsHeaders + + ", otlpMetricsProtocol=" + + otlpMetricsProtocol + + ", otlpMetricsTimeout=" + + otlpMetricsTimeout + + ", otlpMetricsTemporalityPreference=" + + otlpMetricsTemporalityPreference + ", serviceDiscoveryEnabled=" + serviceDiscoveryEnabled + '}'; diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index e184a44fed6..f237e56c0cb 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -143,17 +143,16 @@ import static datadog.trace.api.config.OtlpConfig.Protocol.HTTP_JSON import static datadog.trace.api.config.OtlpConfig.Temporality.CUMULATIVE import static datadog.trace.api.config.OtlpConfig.Temporality.DELTA import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_ENDPOINT +import static datadog.trace.api.config.OtlpConfig.OTLP_ENDPOINT import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_PROTOCOL -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_TIMEOUT -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_HEADERS -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_HEADERS -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT -import static datadog.trace.api.config.OtlpConfig.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE +import static datadog.trace.api.config.OtlpConfig.OTLP_PROTOCOL +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_ENDPOINT +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_HEADERS +import static datadog.trace.api.config.OtlpConfig.OTLP_HEADERS +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_PROTOCOL +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TIMEOUT +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TEMPORALITY_PREFERENCE import datadog.trace.config.inversion.ConfigHelper class ConfigTest extends DDSpecification { @@ -305,11 +304,11 @@ class ConfigTest extends DDSpecification { prop.setProperty(OTEL_METRICS_EXPORTER, "otlp") prop.setProperty(METRICS_OTEL_INTERVAL, "11000") prop.setProperty(METRICS_OTEL_TIMEOUT, "9000") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "api-key=key,other-config-value=value") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, "http/protobuf") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT, "5000") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, "cumulative") + prop.setProperty(OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") + prop.setProperty(OTLP_METRICS_HEADERS, "api-key=key,other-config-value=value") + prop.setProperty(OTLP_METRICS_PROTOCOL, "http/protobuf") + prop.setProperty(OTLP_METRICS_TIMEOUT, "5000") + prop.setProperty(OTLP_METRICS_TEMPORALITY_PREFERENCE, "cumulative") when: Config config = Config.get(prop) @@ -410,12 +409,12 @@ class ConfigTest extends DDSpecification { config.metricsOtelEnabled config.metricsOtelInterval == 11000 config.metricsOtelTimeout == 9000 - config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" - config.otelExporterOtlpMetricsHeaders["api-key"] == "key" - config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" - config.otelExporterOtlpMetricsProtocol == HTTP_PROTOBUF - config.otelExporterOtlpMetricsTimeout == 5000 - config.otelExporterOtlpMetricsTemporalityPreference == CUMULATIVE + config.otlpMetricsEndpoint == "http://localhost:4333/v1/metrics" + config.otlpMetricsHeaders["api-key"] == "key" + config.otlpMetricsHeaders["other-config-value"] == "value" + config.otlpMetricsProtocol == HTTP_PROTOBUF + config.otlpMetricsTimeout == 5000 + config.otlpMetricsTemporalityPreference == CUMULATIVE } @@ -427,11 +426,11 @@ class ConfigTest extends DDSpecification { prop.setProperty(OTEL_METRICS_EXPORTER, "invalid") prop.setProperty(METRICS_OTEL_INTERVAL, "-1") prop.setProperty(METRICS_OTEL_TIMEOUT, "invalid") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, "invalid") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "11") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, "invalid") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT, "-34") - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, "invalid") + prop.setProperty(OTLP_METRICS_ENDPOINT, "invalid") + prop.setProperty(OTLP_METRICS_HEADERS, "11") + prop.setProperty(OTLP_METRICS_PROTOCOL, "invalid") + prop.setProperty(OTLP_METRICS_TIMEOUT, "-34") + prop.setProperty(OTLP_METRICS_TEMPORALITY_PREFERENCE, "invalid") when: Config config = Config.get(prop) @@ -440,11 +439,11 @@ class ConfigTest extends DDSpecification { !config.metricsOtelEnabled config.metricsOtelInterval == 10000 config.metricsOtelTimeout == 7500 - config.otelExporterOtlpMetricsEndpoint == "invalid" - config.otelExporterOtlpMetricsHeaders == [:] - config.otelExporterOtlpMetricsProtocol == GRPC - config.otelExporterOtlpMetricsTimeout == 10000 - config.otelExporterOtlpMetricsTemporalityPreference == DELTA + config.otlpMetricsEndpoint == "invalid" + config.otlpMetricsHeaders == [:] + config.otlpMetricsProtocol == GRPC + config.otlpMetricsTimeout == 10000 + config.otlpMetricsTemporalityPreference == DELTA } def "otel metrics: default values when not set"() { @@ -458,24 +457,24 @@ class ConfigTest extends DDSpecification { !config.metricsOtelEnabled config.metricsOtelInterval == 10000 config.metricsOtelTimeout == 7500 - config.otelExporterOtlpMetricsEndpoint == "http://localhost:4317" - config.otelExporterOtlpMetricsHeaders == [:] - config.otelExporterOtlpMetricsProtocol == GRPC - config.otelExporterOtlpMetricsTimeout == 10000 - config.otelExporterOtlpMetricsTemporalityPreference == DELTA + config.otlpMetricsEndpoint == "http://localhost:4317" + config.otlpMetricsHeaders == [:] + config.otlpMetricsProtocol == GRPC + config.otlpMetricsTimeout == 10000 + config.otlpMetricsTemporalityPreference == DELTA } def "otel metrics: check syntax for attributes and headers"() { setup: def prop = new Properties() - prop.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "api,key=key") + prop.setProperty(OTLP_METRICS_HEADERS, "api,key=key") when: Config config = Config.get(prop) then: - config.otelExporterOtlpMetricsHeaders.size() == 0 + config.otlpMetricsHeaders.size() == 0 } def "otel generic config via system properties - metrics enabled"() { @@ -560,27 +559,27 @@ class ConfigTest extends DDSpecification { def "otel metrics: fallback keys"() { setup: def prop = new Properties() - prop.setProperty(OTEL_EXPORTER_OTLP_PROTOCOL, "http/json") - prop.setProperty(OTEL_EXPORTER_OTLP_ENDPOINT,"http://localhost:4319/") - prop.setProperty(OTEL_EXPORTER_OTLP_HEADERS,"api-key=key,other-config-value=value") + prop.setProperty(OTLP_PROTOCOL, "http/json") + prop.setProperty(OTLP_ENDPOINT,"http://localhost:4319/") + prop.setProperty(OTLP_HEADERS,"api-key=key,other-config-value=value") prop.setProperty(OTEL_EXPORTER_OTLP_TIMEOUT,"1000") when: Config config = Config.get(prop) then: - config.otelExporterOtlpMetricsProtocol == HTTP_JSON - config.otelExporterOtlpMetricsEndpoint == "http://localhost:4319/v1/metrics" - config.otelExporterOtlpMetricsHeaders.size() == 2 - config.otelExporterOtlpMetricsHeaders["api-key"] == "key" - config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" - config.otelExporterOtlpMetricsTimeout == 1000 + config.otlpMetricsProtocol == HTTP_JSON + config.otlpMetricsEndpoint == "http://localhost:4319/v1/metrics" + config.otlpMetricsHeaders.size() == 2 + config.otlpMetricsHeaders["api-key"] == "key" + config.otlpMetricsHeaders["other-config-value"] == "value" + config.otlpMetricsTimeout == 1000 } def "otel metrics: fallback key endpoint"() { setup: def prop = new Properties() - prop.setProperty(OTEL_EXPORTER_OTLP_PROTOCOL, "http/json") + prop.setProperty(OTLP_PROTOCOL, "http/json") prop.setProperty(TRACE_AGENT_URL,"http://192.168.0.3:8126/") when: @@ -588,8 +587,8 @@ class ConfigTest extends DDSpecification { then: config.agentHost == "192.168.0.3" - config.otelExporterOtlpMetricsProtocol == HTTP_JSON - config.otelExporterOtlpMetricsEndpoint == "http://192.168.0.3:4318/v1/metrics" + config.otlpMetricsProtocol == HTTP_JSON + config.otlpMetricsEndpoint == "http://192.168.0.3:4318/v1/metrics" } def "otel metrics: fallback key endpoint 2"() { @@ -602,8 +601,8 @@ class ConfigTest extends DDSpecification { then: config.agentHost == "localhost" - config.otelExporterOtlpMetricsProtocol == GRPC - config.otelExporterOtlpMetricsEndpoint == "http://localhost:4317" + config.otlpMetricsProtocol == GRPC + config.otlpMetricsEndpoint == "http://localhost:4317" } @@ -703,11 +702,11 @@ class ConfigTest extends DDSpecification { System.setProperty(OTEL_METRICS_EXPORTER, "otlp") System.setProperty(METRICS_OTEL_INTERVAL, "11000") System.setProperty(METRICS_OTEL_TIMEOUT, "9000") - System.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") - System.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS, "api-key=key,other-config-value=value") - System.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, "http/protobuf") - System.setProperty(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT, "5000") - System.setProperty(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, "cumulative") + System.setProperty(OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") + System.setProperty(OTLP_METRICS_HEADERS, "api-key=key,other-config-value=value") + System.setProperty(OTLP_METRICS_PROTOCOL, "http/protobuf") + System.setProperty(OTLP_METRICS_TIMEOUT, "5000") + System.setProperty(OTLP_METRICS_TEMPORALITY_PREFERENCE, "cumulative") when: Config config = new Config() @@ -807,12 +806,12 @@ class ConfigTest extends DDSpecification { config.env == "production" config.metricsOtelInterval == 11000 config.metricsOtelTimeout == 9000 - config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" - config.otelExporterOtlpMetricsHeaders["api-key"] == "key" - config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" - config.otelExporterOtlpMetricsProtocol == HTTP_PROTOBUF - config.otelExporterOtlpMetricsTimeout == 5000 - config.otelExporterOtlpMetricsTemporalityPreference == CUMULATIVE + config.otlpMetricsEndpoint == "http://localhost:4333/v1/metrics" + config.otlpMetricsHeaders["api-key"] == "key" + config.otlpMetricsHeaders["other-config-value"] == "value" + config.otlpMetricsProtocol == HTTP_PROTOBUF + config.otlpMetricsTimeout == 5000 + config.otlpMetricsTemporalityPreference == CUMULATIVE } def "specify overrides via env vars"() { @@ -865,12 +864,12 @@ class ConfigTest extends DDSpecification { config.metricsOtelEnabled config.metricsOtelInterval == 11000 config.metricsOtelTimeout == 9000 - config.otelExporterOtlpMetricsEndpoint == "http://localhost:4333/v1/metrics" - config.otelExporterOtlpMetricsHeaders["api-key"] == "key" - config.otelExporterOtlpMetricsHeaders["other-config-value"] == "value" - config.otelExporterOtlpMetricsProtocol == HTTP_PROTOBUF - config.otelExporterOtlpMetricsTimeout == 5000 - config.otelExporterOtlpMetricsTemporalityPreference == CUMULATIVE + config.otlpMetricsEndpoint == "http://localhost:4333/v1/metrics" + config.otlpMetricsHeaders["api-key"] == "key" + config.otlpMetricsHeaders["other-config-value"] == "value" + config.otlpMetricsProtocol == HTTP_PROTOBUF + config.otlpMetricsTimeout == 5000 + config.otlpMetricsTemporalityPreference == CUMULATIVE } def "sys props override env vars"() { From 501f78e43b718e2c24f2bb09276ceb8f88790843 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 5 Nov 2025 23:57:11 +0000 Subject: [PATCH 33/38] Add new DD metrics keys --- metadata/supported-configurations.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index ce5af9856b1..f003bba5b71 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -285,8 +285,15 @@ "DD_MEASURE_METHODS": ["A"], "DD_MESSAGE_BROKER_SPLIT_BY_DESTINATION": ["A"], "DD_METRICS_OTEL_ENABLED": ["A"], + "DD_METRICS_OTEL_INTERVAL": ["A"], + "DD_METRICS_OTEL_TIMEOUT": ["A"], "DD_OBFUSCATION_QUERY_STRING_REGEXP": ["A"], "DD_OPTIMIZED_MAP_ENABLED": ["A"], + "DD_OTLP_METRICS_ENDPOINT": ["A"], + "DD_OTLP_METRICS_HEADERS": ["A"], + "DD_OTLP_METRICS_PROTOCOL": ["A"], + "DD_OTLP_METRICS_TIMEOUT": ["A"], + "DD_OTLP_METRICS_TEMPORALITY_PREFERENCE": ["A"], "DD_PIPELINE_EXECUTION_ID": ["A"], "DD_PRIMARY_TAG": ["A"], "DD_PRIORITIZATION_TYPE": ["A"], From 2d16f0a03511a0eee4c503ab22f5bb07e8b04220 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Thu, 6 Nov 2025 00:31:56 +0000 Subject: [PATCH 34/38] Update test expectations: default protocol is now HTTP/PROTOBUF --- .../datadog/trace/api/ConfigTest.groovy | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index f237e56c0cb..5a09872bdc3 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -153,6 +153,7 @@ import static datadog.trace.api.config.OtlpConfig.OTLP_HEADERS import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_PROTOCOL import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TIMEOUT import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TEMPORALITY_PREFERENCE +import static datadog.trace.api.config.OtlpConfig.OTLP_TIMEOUT import datadog.trace.config.inversion.ConfigHelper class ConfigTest extends DDSpecification { @@ -194,7 +195,6 @@ class ConfigTest extends DDSpecification { private static final OTEL_RESOURCE_ATTRIBUTES_ENV = "OTEL_RESOURCE_ATTRIBUTES" private static final DD_METRICS_OTEL_ENABLED_ENV = "DD_METRICS_OTEL_ENABLED" - private static final OTEL_METRICS_EXPORTER_ENV = "OTEL_METRICS_EXPORTER" private static final OTEL_METRIC_EXPORT_TIMEOUT_ENV = "OTEL_METRIC_EXPORT_TIMEOUT" private static final OTEL_METRIC_EXPORT_INTERVAL_ENV = "OTEL_METRIC_EXPORT_INTERVAL" private static final OTEL_EXPORTER_OTLP_METRICS_ENDPOINT_ENV = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" @@ -301,7 +301,6 @@ class ConfigTest extends DDSpecification { prop.setProperty(JDK_SOCKET_ENABLED, "false") prop.setProperty(METRICS_OTEL_ENABLED, "True") - prop.setProperty(OTEL_METRICS_EXPORTER, "otlp") prop.setProperty(METRICS_OTEL_INTERVAL, "11000") prop.setProperty(METRICS_OTEL_TIMEOUT, "9000") prop.setProperty(OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") @@ -423,7 +422,6 @@ class ConfigTest extends DDSpecification { def prop = new Properties() prop.setProperty(METRICS_OTEL_ENABLED, "youhou") - prop.setProperty(OTEL_METRICS_EXPORTER, "invalid") prop.setProperty(METRICS_OTEL_INTERVAL, "-1") prop.setProperty(METRICS_OTEL_TIMEOUT, "invalid") prop.setProperty(OTLP_METRICS_ENDPOINT, "invalid") @@ -441,8 +439,8 @@ class ConfigTest extends DDSpecification { config.metricsOtelTimeout == 7500 config.otlpMetricsEndpoint == "invalid" config.otlpMetricsHeaders == [:] - config.otlpMetricsProtocol == GRPC - config.otlpMetricsTimeout == 10000 + config.otlpMetricsProtocol == HTTP_PROTOBUF + config.otlpMetricsTimeout == 7500 config.otlpMetricsTemporalityPreference == DELTA } @@ -457,10 +455,10 @@ class ConfigTest extends DDSpecification { !config.metricsOtelEnabled config.metricsOtelInterval == 10000 config.metricsOtelTimeout == 7500 - config.otlpMetricsEndpoint == "http://localhost:4317" + config.otlpMetricsEndpoint == "http://localhost:4318/v1/metrics" config.otlpMetricsHeaders == [:] - config.otlpMetricsProtocol == GRPC - config.otlpMetricsTimeout == 10000 + config.otlpMetricsProtocol == HTTP_PROTOBUF + config.otlpMetricsTimeout == 7500 config.otlpMetricsTemporalityPreference == DELTA } @@ -560,9 +558,9 @@ class ConfigTest extends DDSpecification { setup: def prop = new Properties() prop.setProperty(OTLP_PROTOCOL, "http/json") - prop.setProperty(OTLP_ENDPOINT,"http://localhost:4319/") + prop.setProperty(OTLP_ENDPOINT,"http://localhost:4319") prop.setProperty(OTLP_HEADERS,"api-key=key,other-config-value=value") - prop.setProperty(OTEL_EXPORTER_OTLP_TIMEOUT,"1000") + prop.setProperty(OTLP_TIMEOUT,"1000") when: Config config = Config.get(prop) @@ -580,7 +578,7 @@ class ConfigTest extends DDSpecification { setup: def prop = new Properties() prop.setProperty(OTLP_PROTOCOL, "http/json") - prop.setProperty(TRACE_AGENT_URL,"http://192.168.0.3:8126/") + prop.setProperty(TRACE_AGENT_URL,"http://192.168.0.3:8126") when: Config config = Config.get(prop) @@ -601,8 +599,8 @@ class ConfigTest extends DDSpecification { then: config.agentHost == "localhost" - config.otlpMetricsProtocol == GRPC - config.otlpMetricsEndpoint == "http://localhost:4317" + config.otlpMetricsProtocol == HTTP_PROTOBUF + config.otlpMetricsEndpoint == "http://localhost:4318/v1/metrics" } @@ -699,7 +697,6 @@ class ConfigTest extends DDSpecification { System.setProperty(PREFIX + METRICS_OTEL_ENABLED, "True") System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production") - System.setProperty(OTEL_METRICS_EXPORTER, "otlp") System.setProperty(METRICS_OTEL_INTERVAL, "11000") System.setProperty(METRICS_OTEL_TIMEOUT, "9000") System.setProperty(OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") @@ -832,7 +829,6 @@ class ConfigTest extends DDSpecification { environmentVariables.set(DD_TRACE_HEADER_TAGS, "*") environmentVariables.set(DD_METRICS_OTEL_ENABLED_ENV, "True") environmentVariables.set(OTEL_RESOURCE_ATTRIBUTES_ENV, "service.name=my=app,service.version=1.0.0,deployment.environment=production") - environmentVariables.set(OTEL_METRICS_EXPORTER_ENV, "otlp") environmentVariables.set(OTEL_METRIC_EXPORT_INTERVAL_ENV, "11000") environmentVariables.set(OTEL_METRIC_EXPORT_TIMEOUT_ENV, "9000") environmentVariables.set(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT_ENV, "http://localhost:4333/v1/metrics") From a75665da78714d33ac0d08137fc3119a5b86b057 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Thu, 6 Nov 2025 00:48:02 +0000 Subject: [PATCH 35/38] Move OTel mappings out of Config --- .../main/java/datadog/trace/api/Config.java | 83 +++++-------------- 1 file changed, 23 insertions(+), 60 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index f2906a44c76..e0f3da1340a 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -446,15 +446,11 @@ import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED; import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL; import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT; -import static datadog.trace.api.config.OtlpConfig.OTLP_ENDPOINT; -import static datadog.trace.api.config.OtlpConfig.OTLP_HEADERS; import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_ENDPOINT; import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_HEADERS; import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_PROTOCOL; import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TEMPORALITY_PREFERENCE; import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TIMEOUT; -import static datadog.trace.api.config.OtlpConfig.OTLP_PROTOCOL; -import static datadog.trace.api.config.OtlpConfig.OTLP_TIMEOUT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_API_KEY_FILE_OLD; @@ -1861,67 +1857,34 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins metricsOtelEnabled = configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED); - - Integer tmpOtelMetricExportTimeout = configProvider.getInteger(METRICS_OTEL_TIMEOUT); + metricsOtelInterval = + configProvider.getInteger(METRICS_OTEL_INTERVAL, DEFAULT_METRICS_OTEL_INTERVAL); metricsOtelTimeout = - (tmpOtelMetricExportTimeout == null || tmpOtelMetricExportTimeout < 0) - ? DEFAULT_METRICS_OTEL_TIMEOUT - : tmpOtelMetricExportTimeout; + configProvider.getInteger(METRICS_OTEL_TIMEOUT, DEFAULT_METRICS_OTEL_TIMEOUT); - Integer tmpOtelMetricExportInterval = configProvider.getInteger(METRICS_OTEL_INTERVAL); - metricsOtelInterval = - (tmpOtelMetricExportInterval == null || tmpOtelMetricExportInterval < 0) - ? DEFAULT_METRICS_OTEL_INTERVAL - : tmpOtelMetricExportInterval; - - Map tmpOtelExporterOtlpMetricsHeaders = - configProvider.getMergedMap(OTLP_METRICS_HEADERS, '='); - if (tmpOtelExporterOtlpMetricsHeaders.isEmpty()) { - tmpOtelExporterOtlpMetricsHeaders = configProvider.getMergedMap(OTLP_HEADERS, '='); - } - otlpMetricsHeaders = tmpOtelExporterOtlpMetricsHeaders; - - OtlpConfig.Protocol tmpOtelExporterOtlpMetricsProtocol = - configProvider.getEnum(OTLP_METRICS_PROTOCOL, OtlpConfig.Protocol.class, null); - if (tmpOtelExporterOtlpMetricsProtocol == null) { - tmpOtelExporterOtlpMetricsProtocol = - configProvider.getEnum( - OTLP_PROTOCOL, OtlpConfig.Protocol.class, OtlpConfig.Protocol.HTTP_PROTOBUF); - } - otlpMetricsProtocol = tmpOtelExporterOtlpMetricsProtocol; - // TODO: log warning and switch protocol to default if we don't support the selected protocol? - - String tmpOtelExporterOtlpMetricsEndpoint = configProvider.getString(OTLP_METRICS_ENDPOINT); - if (tmpOtelExporterOtlpMetricsEndpoint == null) { - boolean isHttp = !otlpMetricsProtocol.equals(OtlpConfig.Protocol.GRPC); - String tmpOtelExporterOtlpEndpoint = configProvider.getString(OTLP_ENDPOINT); - if (null == tmpOtelExporterOtlpEndpoint) { - tmpOtelExporterOtlpMetricsEndpoint = - isHttp - ? "http://" - + agentHost - + ':' - + DEFAULT_OTLP_HTTP_PORT - + '/' - + DEFAULT_OTLP_HTTP_METRIC_ENDPOINT - : "http://" + agentHost + ':' + DEFAULT_OTLP_GRPC_PORT; + otlpMetricsHeaders = configProvider.getMergedMap(OTLP_METRICS_HEADERS, '='); + otlpMetricsProtocol = + configProvider.getEnum( + OTLP_METRICS_PROTOCOL, OtlpConfig.Protocol.class, OtlpConfig.Protocol.HTTP_PROTOBUF); + otlpMetricsTimeout = + configProvider.getInteger( + OTLP_METRICS_TIMEOUT, Math.min(metricsOtelTimeout, DEFAULT_METRICS_OTEL_TIMEOUT)); + + String otlpMetricsEndpointFromEnvironment = configProvider.getString(OTLP_METRICS_ENDPOINT); + if (otlpMetricsEndpointFromEnvironment == null) { + if (otlpMetricsProtocol == OtlpConfig.Protocol.GRPC) { + otlpMetricsEndpointFromEnvironment = "http://" + agentHost + ':' + DEFAULT_OTLP_GRPC_PORT; } else { - tmpOtelExporterOtlpMetricsEndpoint = - isHttp - ? tmpOtelExporterOtlpEndpoint + '/' + DEFAULT_OTLP_HTTP_METRIC_ENDPOINT - : tmpOtelExporterOtlpEndpoint; + otlpMetricsEndpointFromEnvironment = + "http://" + + agentHost + + ':' + + DEFAULT_OTLP_HTTP_PORT + + '/' + + DEFAULT_OTLP_HTTP_METRIC_ENDPOINT; } } - otlpMetricsEndpoint = tmpOtelExporterOtlpMetricsEndpoint; - - Integer tmpOtelExporterOtlpMetricsTimeout = configProvider.getInteger(OTLP_METRICS_TIMEOUT); - if (null == tmpOtelExporterOtlpMetricsTimeout) { - tmpOtelExporterOtlpMetricsTimeout = configProvider.getInteger(OTLP_TIMEOUT); - } - otlpMetricsTimeout = - (tmpOtelExporterOtlpMetricsTimeout == null || tmpOtelExporterOtlpMetricsTimeout < 0) - ? Math.min(metricsOtelTimeout, DEFAULT_METRICS_OTEL_TIMEOUT) - : tmpOtelExporterOtlpMetricsTimeout; + otlpMetricsEndpoint = otlpMetricsEndpointFromEnvironment; otlpMetricsTemporalityPreference = configProvider.getEnum( From 80d2365aca284b8e0c4e3a287a2058dbd0339469 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Thu, 6 Nov 2025 02:02:13 +0000 Subject: [PATCH 36/38] Implement OTel metrics mappings in OtelEnvironmentConfigSource --- .../datadog/trace/api/ConfigTest.groovy | 68 ++++++++----- .../provider/OtelEnvironmentConfigSource.java | 95 +++++++++++++++++-- 2 files changed, 130 insertions(+), 33 deletions(-) diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 5a09872bdc3..679810fda04 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -191,17 +191,37 @@ class ConfigTest extends DDSpecification { private static final DD_LLMOBS_ML_APP_ENV = "DD_LLMOBS_ML_APP" private static final DD_LLMOBS_AGENTLESS_ENABLED_ENV = "DD_LLMOBS_AGENTLESS_ENABLED" - private static final OTEL_RESOURCE_ATTRIBUTES_PROP = "otel.resource.attributes" + private static final DD_METRICS_OTEL_ENABLED_ENV = "DD_METRICS_OTEL_ENABLED" + private static final DD_METRICS_OTEL_ENABLED_PROP = "dd.metrics.otel.enabled" + private static final OTEL_RESOURCE_ATTRIBUTES_ENV = "OTEL_RESOURCE_ATTRIBUTES" + private static final OTEL_RESOURCE_ATTRIBUTES_PROP = "otel.resource.attributes" - private static final DD_METRICS_OTEL_ENABLED_ENV = "DD_METRICS_OTEL_ENABLED" private static final OTEL_METRIC_EXPORT_TIMEOUT_ENV = "OTEL_METRIC_EXPORT_TIMEOUT" + private static final OTEL_METRIC_EXPORT_TIMEOUT_PROP = "otel.metric.export.timeout" private static final OTEL_METRIC_EXPORT_INTERVAL_ENV = "OTEL_METRIC_EXPORT_INTERVAL" + private static final OTEL_METRIC_EXPORT_INTERVAL_PROP = "otel.metric.export.interval" + + private static final OTEL_EXPORTER_OTLP_ENDPOINT_ENV = "OTEL_EXPORTER_OTLP_ENDPOINT" + private static final OTEL_EXPORTER_OTLP_ENDPOINT_PROP = "otel.exporter.otlp.endpoint" + private static final OTEL_EXPORTER_OTLP_HEADERS_ENV = "OTEL_EXPORTER_OTLP_HEADERS" + private static final OTEL_EXPORTER_OTLP_HEADERS_PROP = "otel.exporter.otlp.headers" + private static final OTEL_EXPORTER_OTLP_PROTOCOL_ENV = "OTEL_EXPORTER_OTLP_PROTOCOL" + private static final OTEL_EXPORTER_OTLP_PROTOCOL_PROP = "otel.exporter.otlp.protocol" + private static final OTEL_EXPORTER_OTLP_TIMEOUT_ENV = "OTEL_EXPORTER_OTLP_TIMEOUT" + private static final OTEL_EXPORTER_OTLP_TIMEOUT_PROP = "otel.exporter.otlp.timeout" + private static final OTEL_EXPORTER_OTLP_METRICS_ENDPOINT_ENV = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" + private static final OTEL_EXPORTER_OTLP_METRICS_ENDPOINT_PROP = "otel.exporter.otlp.metrics.endpoint" private static final OTEL_EXPORTER_OTLP_METRICS_HEADERS_ENV = "OTEL_EXPORTER_OTLP_METRICS_HEADERS" + private static final OTEL_EXPORTER_OTLP_METRICS_HEADERS_PROP = "otel.exporter.otlp.metrics.headers" private static final OTEL_EXPORTER_OTLP_METRICS_PROTOCOL_ENV = "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL" + private static final OTEL_EXPORTER_OTLP_METRICS_PROTOCOL_PROP = "otel.exporter.otlp.metrics.protocol" private static final OTEL_EXPORTER_OTLP_METRICS_TIMEOUT_ENV = "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT" + private static final OTEL_EXPORTER_OTLP_METRICS_TIMEOUT_PROP = "otel.exporter.otlp.metrics.timeout" + private static final OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE_ENV = "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE" + private static final OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE_PROP = "otel.exporter.otlp.metrics.temporality.preference" def setup() { FixedCapturedEnvironment.useFixedEnv([:]) @@ -435,12 +455,12 @@ class ConfigTest extends DDSpecification { then: !config.metricsOtelEnabled - config.metricsOtelInterval == 10000 + config.metricsOtelInterval == -1 config.metricsOtelTimeout == 7500 config.otlpMetricsEndpoint == "invalid" config.otlpMetricsHeaders == [:] config.otlpMetricsProtocol == HTTP_PROTOBUF - config.otlpMetricsTimeout == 7500 + config.otlpMetricsTimeout == -34 config.otlpMetricsTemporalityPreference == DELTA } @@ -556,14 +576,14 @@ class ConfigTest extends DDSpecification { def "otel metrics: fallback keys"() { setup: - def prop = new Properties() - prop.setProperty(OTLP_PROTOCOL, "http/json") - prop.setProperty(OTLP_ENDPOINT,"http://localhost:4319") - prop.setProperty(OTLP_HEADERS,"api-key=key,other-config-value=value") - prop.setProperty(OTLP_TIMEOUT,"1000") + System.setProperty(DD_METRICS_OTEL_ENABLED_PROP, "true") + System.setProperty(OTEL_EXPORTER_OTLP_PROTOCOL_PROP, "http/json") + System.setProperty(OTEL_EXPORTER_OTLP_ENDPOINT_PROP,"http://localhost:4319") + System.setProperty(OTEL_EXPORTER_OTLP_HEADERS_PROP,"api-key=key,other-config-value=value") + System.setProperty(OTEL_EXPORTER_OTLP_TIMEOUT_PROP,"1000") when: - Config config = Config.get(prop) + Config config = new Config() then: config.otlpMetricsProtocol == HTTP_JSON @@ -576,12 +596,12 @@ class ConfigTest extends DDSpecification { def "otel metrics: fallback key endpoint"() { setup: - def prop = new Properties() - prop.setProperty(OTLP_PROTOCOL, "http/json") - prop.setProperty(TRACE_AGENT_URL,"http://192.168.0.3:8126") + System.setProperty(DD_METRICS_OTEL_ENABLED_PROP, "true") + System.setProperty(OTEL_EXPORTER_OTLP_PROTOCOL_PROP, "http/json") + System.setProperty(PREFIX + TRACE_AGENT_URL,"http://192.168.0.3:8126") when: - Config config = Config.get(prop) + Config config = new Config() then: config.agentHost == "192.168.0.3" @@ -591,11 +611,11 @@ class ConfigTest extends DDSpecification { def "otel metrics: fallback key endpoint 2"() { setup: - def prop = new Properties() - prop.setProperty(TRACE_AGENT_URL,"'/tmp/ddagent/trace.sock'") + System.setProperty(DD_METRICS_OTEL_ENABLED_PROP, "true") + System.setProperty(PREFIX + TRACE_AGENT_URL,"'/tmp/ddagent/trace.sock'") when: - Config config = Config.get(prop) + Config config = new Config() then: config.agentHost == "localhost" @@ -696,14 +716,14 @@ class ConfigTest extends DDSpecification { System.setProperty(PREFIX + TRACE_X_DATADOG_TAGS_MAX_LENGTH, "128") System.setProperty(PREFIX + METRICS_OTEL_ENABLED, "True") + System.setProperty(OTEL_METRIC_EXPORT_INTERVAL_PROP, "11000") + System.setProperty(OTEL_METRIC_EXPORT_TIMEOUT_PROP, "9000") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT_PROP, "http://localhost:4333/v1/metrics") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_HEADERS_PROP, "api-key=key,other-config-value=value") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL_PROP, "http/protobuf") + System.setProperty(OTEL_EXPORTER_OTLP_TIMEOUT_PROP, "5000") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE_PROP, "cumulative") System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production") - System.setProperty(METRICS_OTEL_INTERVAL, "11000") - System.setProperty(METRICS_OTEL_TIMEOUT, "9000") - System.setProperty(OTLP_METRICS_ENDPOINT, "http://localhost:4333/v1/metrics") - System.setProperty(OTLP_METRICS_HEADERS, "api-key=key,other-config-value=value") - System.setProperty(OTLP_METRICS_PROTOCOL, "http/protobuf") - System.setProperty(OTLP_METRICS_TIMEOUT, "5000") - System.setProperty(OTLP_METRICS_TEMPORALITY_PREFERENCE, "cumulative") when: Config config = new Config() diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java index c6169be323b..8423a0fd2d7 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java @@ -9,6 +9,13 @@ import static datadog.trace.api.config.GeneralConfig.TAGS; import static datadog.trace.api.config.GeneralConfig.VERSION; import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED; +import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL; +import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_ENDPOINT; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_HEADERS; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_PROTOCOL; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TEMPORALITY_PREFERENCE; +import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TIMEOUT; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_ENABLED; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_EXTENSIONS_PATH; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_OTEL_ENABLED; @@ -73,8 +80,8 @@ public ConfigOrigin origin() { } OtelEnvironmentConfigSource(Properties datadogConfigFile) { - this.enabled = traceOtelEnabled() || metricsOtelEnabled(); this.datadogConfigFile = datadogConfigFile; + this.enabled = traceOtelEnabled() || metricsOtelEnabled(); if (enabled) { setupOtelEnvironment(); @@ -102,15 +109,21 @@ private void setupOtelEnvironment() { } capture(LOG_LEVEL, logLevel); capture(SERVICE_NAME, serviceName); - capture(RUNTIME_METRICS_ENABLED, mapDataCollection("metrics")); - mapDataCollection("logs"); // check setting, but no need to capture it if (traceOtelEnabled()) { - setupOtelTraceEnvironment(); + setupTraceOtelEnvironment(); + } + + if (metricsOtelEnabled()) { + setupMetricsOtelEnvironment(); + } else { + capture(RUNTIME_METRICS_ENABLED, mapDataCollection("metrics")); } + + mapDataCollection("logs"); // check setting, but no need to capture it } - private void setupOtelTraceEnvironment() { + private void setupTraceOtelEnvironment() { String propagators = getOtelProperty("otel.propagators", "dd." + TRACE_PROPAGATION_STYLE); String tracesSampler = getOtelProperty("otel.traces.sampler", "dd." + TRACE_SAMPLE_RATE); String requestHeaders = getOtelHeaders("request-headers", "dd." + REQUEST_HEADER_TAGS); @@ -124,6 +137,38 @@ private void setupOtelTraceEnvironment() { capture(TRACE_EXTENSIONS_PATH, extensions); } + private void setupMetricsOtelEnvironment() { + capture( + METRICS_OTEL_INTERVAL, + getOtelProperty("otel.metric.export.interval", "dd." + METRICS_OTEL_INTERVAL)); + capture( + METRICS_OTEL_TIMEOUT, + getOtelProperty("otel.metric.export.timeout", "dd." + METRICS_OTEL_TIMEOUT)); + + String exporter = getOtelProperty("otel.metrics.exporter"); + if (exporter == null || "otlp".equalsIgnoreCase(exporter)) { + capture( + OTLP_METRICS_HEADERS, + getOtelOtlpProperty("metrics", "headers", "dd." + OTLP_METRICS_HEADERS)); + capture( + OTLP_METRICS_PROTOCOL, + getOtelOtlpProperty("metrics", "protocol", "dd." + OTLP_METRICS_PROTOCOL)); + capture( + OTLP_METRICS_TIMEOUT, + getOtelOtlpProperty("metrics", "timeout", "dd." + OTLP_METRICS_TIMEOUT)); + capture( + OTLP_METRICS_ENDPOINT, + getOtelOtlpProperty("metrics", "endpoint", "dd." + OTLP_METRICS_ENDPOINT)); + capture( + OTLP_METRICS_TEMPORALITY_PREFERENCE, + getOtelProperty( + "otel.exporter.otlp.metrics.temporality.preference", + "dd." + OTLP_METRICS_TEMPORALITY_PREFERENCE)); + } else { + capture(RUNTIME_METRICS_ENABLED, mapDataCollection("metrics")); + } + } + private boolean traceOtelEnabled() { String enabled = getDatadogProperty("dd." + TRACE_OTEL_ENABLED); if (null != enabled) { @@ -177,6 +222,38 @@ private String getOtelProperty(String sysProp) { return value; } + /** + * Gets an OpenTelemetry OTLP property, checking the signal specific key before the general one. + * + *

Checks system properties, environment variables, and the optional OpenTelemetry config file. + * If the equivalent Datadog property is also set then log a warning and return {@code null}. + */ + private String getOtelOtlpProperty(String signal, String subkey, String ddSysProp) { + String otelKey = "otel.exporter.otlp." + signal + "." + subkey; + String otelValue = getOtelProperty(otelKey); + if (null == otelValue) { + otelKey = "otel.exporter.otlp." + subkey; + otelValue = getOtelProperty(otelKey); + if ("endpoint".equals(subkey) + && otelValue != null + && !"grpc".equalsIgnoreCase(otelEnvironment.get(OTLP_METRICS_PROTOCOL))) { + otelValue = otelValue + "/v1/metrics"; + } + } + if (null == otelValue) { + return null; + } + String ddValue = getDatadogProperty(ddSysProp); + if (null != ddValue) { + String otelEnvVar = toEnvVar(otelKey); + log.warn("Both {} and {} are set, ignoring {}", toEnvVar(ddSysProp), otelEnvVar, otelEnvVar); + OtelEnvMetricCollectorProvider.get() + .setHidingOtelEnvVarMetric(toEnvVarLowerCase(otelKey), toEnvVarLowerCase(ddSysProp)); + return null; + } + return otelValue; + } + /** * Gets a Datadog property. * @@ -343,8 +420,8 @@ private String mapSampleRate(String tracesSampler) { } /** Maps an OpenTelemetry exporter setting to the equivalent Datadog collection setting. */ - private String mapDataCollection(String type) { - String exporter = getOtelProperty("otel." + type + ".exporter"); + private String mapDataCollection(String signal) { + String exporter = getOtelProperty("otel." + signal + ".exporter"); if (null == exporter) { return null; } @@ -353,9 +430,9 @@ private String mapDataCollection(String type) { return "false"; // currently we only accept "none" which maps to disable data collection } - log.warn("OTEL_{}_EXPORTER={} is not supported", type, exporter.toUpperCase(Locale.ROOT)); + log.warn("OTEL_{}_EXPORTER={} is not supported", signal, exporter.toUpperCase(Locale.ROOT)); OtelEnvMetricCollectorProvider.get() - .setUnsupportedOtelEnvVarMetric("otel_" + type + "_exporter"); + .setUnsupportedOtelEnvVarMetric("otel_" + signal + "_exporter"); return null; } From 5b3d5ae54056473dac75060cbc4e7d220d42dbf1 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Thu, 6 Nov 2025 02:11:05 +0000 Subject: [PATCH 37/38] Cleanup --- .../datadog/trace/api/config/OtlpConfig.java | 5 ----- .../groovy/datadog/trace/api/ConfigTest.groovy | 17 +++++++---------- .../provider/OtelEnvironmentConfigSource.java | 1 + 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java index 29cc7a8241a..29d7e144ca4 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java @@ -6,11 +6,6 @@ public final class OtlpConfig { public static final String METRICS_OTEL_INTERVAL = "metrics.otel.interval"; public static final String METRICS_OTEL_TIMEOUT = "metrics.otel.timeout"; - public static final String OTLP_ENDPOINT = "otlp.endpoint"; - public static final String OTLP_HEADERS = "otlp.headers"; - public static final String OTLP_PROTOCOL = "otlp.protocol"; - public static final String OTLP_TIMEOUT = "otlp.timeout"; - public static final String OTLP_METRICS_ENDPOINT = "otlp.metrics.endpoint"; public static final String OTLP_METRICS_HEADERS = "otlp.metrics.headers"; public static final String OTLP_METRICS_PROTOCOL = "otlp.metrics.protocol"; diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 679810fda04..866d628dd13 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -6,7 +6,6 @@ import datadog.trace.bootstrap.config.provider.ConfigConverter import datadog.trace.bootstrap.config.provider.ConfigProvider import datadog.trace.test.util.DDSpecification import datadog.trace.util.throwable.FatalAgentMisconfigurationError -import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_OTEL_ENABLED import static datadog.trace.api.ConfigDefaults.DEFAULT_HTTP_CLIENT_ERROR_STATUSES import static datadog.trace.api.ConfigDefaults.DEFAULT_HTTP_SERVER_ERROR_STATUSES import static datadog.trace.api.ConfigDefaults.DEFAULT_PARTIAL_FLUSH_MIN_SPANS @@ -137,23 +136,18 @@ import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_OPERATION_RUL import static datadog.trace.api.config.TracerConfig.TRACE_SAMPLING_SERVICE_RULES import static datadog.trace.api.config.TracerConfig.TRACE_X_DATADOG_TAGS_MAX_LENGTH import static datadog.trace.api.config.TracerConfig.WRITER_TYPE -import static datadog.trace.api.config.OtlpConfig.Protocol.GRPC import static datadog.trace.api.config.OtlpConfig.Protocol.HTTP_PROTOBUF import static datadog.trace.api.config.OtlpConfig.Protocol.HTTP_JSON import static datadog.trace.api.config.OtlpConfig.Temporality.CUMULATIVE import static datadog.trace.api.config.OtlpConfig.Temporality.DELTA import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED -import static datadog.trace.api.config.OtlpConfig.OTLP_ENDPOINT import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT -import static datadog.trace.api.config.OtlpConfig.OTLP_PROTOCOL import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_ENDPOINT import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_HEADERS -import static datadog.trace.api.config.OtlpConfig.OTLP_HEADERS import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_PROTOCOL import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TIMEOUT import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TEMPORALITY_PREFERENCE -import static datadog.trace.api.config.OtlpConfig.OTLP_TIMEOUT import datadog.trace.config.inversion.ConfigHelper class ConfigTest extends DDSpecification { @@ -191,6 +185,9 @@ class ConfigTest extends DDSpecification { private static final DD_LLMOBS_ML_APP_ENV = "DD_LLMOBS_ML_APP" private static final DD_LLMOBS_AGENTLESS_ENABLED_ENV = "DD_LLMOBS_AGENTLESS_ENABLED" + private static final DD_TRACE_OTEL_ENABLED_ENV = "DD_TRACE_OTEL_ENABLED" + private static final DD_TRACE_OTEL_ENABLED_PROP = "dd.trace.otel.enabled" + private static final DD_METRICS_OTEL_ENABLED_ENV = "DD_METRICS_OTEL_ENABLED" private static final DD_METRICS_OTEL_ENABLED_PROP = "dd.metrics.otel.enabled" @@ -497,7 +494,7 @@ class ConfigTest extends DDSpecification { def "otel generic config via system properties - metrics enabled"() { setup: - System.setProperty(PREFIX + METRICS_OTEL_ENABLED, "true") + System.setProperty(DD_METRICS_OTEL_ENABLED_PROP, "true") System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") System.setProperty("otel.log.level", "warning") @@ -517,7 +514,7 @@ class ConfigTest extends DDSpecification { def "otel generic config via system properties - trace enabled"() { setup: - System.setProperty(PREFIX + TRACE_OTEL_ENABLED, "true") + System.setProperty(DD_TRACE_OTEL_ENABLED_PROP, "true") System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") System.setProperty("otel.log.level", "warning") @@ -557,7 +554,7 @@ class ConfigTest extends DDSpecification { def "otel generic config via env var - traces enabled"() { setup: - environmentVariables.set("DD_TRACE_OTEL_ENABLED", "true") + environmentVariables.set(DD_TRACE_OTEL_ENABLED_ENV, "true") environmentVariables.set(OTEL_RESOURCE_ATTRIBUTES_ENV, "service.name=my=app,service.version=1.0.0,deployment.environment=production, message=blahblah") environmentVariables.set("OTEL_LOG_LEVEL", "error") when: @@ -715,7 +712,7 @@ class ConfigTest extends DDSpecification { System.setProperty(PREFIX + DYNAMIC_INSTRUMENTATION_EXCLUDE_FILES, "exclude file") System.setProperty(PREFIX + TRACE_X_DATADOG_TAGS_MAX_LENGTH, "128") - System.setProperty(PREFIX + METRICS_OTEL_ENABLED, "True") + System.setProperty(DD_METRICS_OTEL_ENABLED_PROP, "True") System.setProperty(OTEL_METRIC_EXPORT_INTERVAL_PROP, "11000") System.setProperty(OTEL_METRIC_EXPORT_TIMEOUT_PROP, "9000") System.setProperty(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT_PROP, "http://localhost:4333/v1/metrics") diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java index 8423a0fd2d7..b6d06f11706 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java @@ -234,6 +234,7 @@ private String getOtelOtlpProperty(String signal, String subkey, String ddSysPro if (null == otelValue) { otelKey = "otel.exporter.otlp." + subkey; otelValue = getOtelProperty(otelKey); + // special case when using general endpoint as fallback: append relevant metric endpoint if ("endpoint".equals(subkey) && otelValue != null && !"grpc".equalsIgnoreCase(otelEnvironment.get(OTLP_METRICS_PROTOCOL))) { From 90ccc7b112d4789e40f49419b3bbba9f970b399b Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Thu, 6 Nov 2025 02:46:19 +0000 Subject: [PATCH 38/38] Warn when any OTel timeouts/intervals are configured with negative values --- .../main/java/datadog/trace/api/Config.java | 29 +++++++++++++++---- .../datadog/trace/api/ConfigTest.groovy | 4 +-- .../provider/OtelEnvironmentConfigSource.java | 6 ++-- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index e0f3da1340a..a28a1729919 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -1857,18 +1857,35 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins metricsOtelEnabled = configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED); - metricsOtelInterval = + + int otelInterval = configProvider.getInteger(METRICS_OTEL_INTERVAL, DEFAULT_METRICS_OTEL_INTERVAL); - metricsOtelTimeout = - configProvider.getInteger(METRICS_OTEL_TIMEOUT, DEFAULT_METRICS_OTEL_TIMEOUT); + if (otelInterval < 0) { + log.warn("Invalid OTel metrics interval: {}. The value must be positive", otelInterval); + otelInterval = DEFAULT_METRICS_OTEL_INTERVAL; + } + metricsOtelInterval = otelInterval; + + int otelTimeout = configProvider.getInteger(METRICS_OTEL_TIMEOUT, DEFAULT_METRICS_OTEL_TIMEOUT); + if (otelTimeout < 0) { + log.warn("Invalid OTel metrics timeout: {}. The value must be positive", otelTimeout); + otelTimeout = DEFAULT_METRICS_OTEL_TIMEOUT; + } + metricsOtelTimeout = otelTimeout; + + // keep OTLP default timeout below the overall export timeout + int defaultOtlpTimeout = Math.min(metricsOtelTimeout, DEFAULT_METRICS_OTEL_TIMEOUT); + int otlpTimeout = configProvider.getInteger(OTLP_METRICS_TIMEOUT, defaultOtlpTimeout); + if (otlpTimeout < 0) { + log.warn("Invalid OTLP metrics timeout: {}. The value must be positive", otlpTimeout); + otlpTimeout = defaultOtlpTimeout; + } + otlpMetricsTimeout = otlpTimeout; otlpMetricsHeaders = configProvider.getMergedMap(OTLP_METRICS_HEADERS, '='); otlpMetricsProtocol = configProvider.getEnum( OTLP_METRICS_PROTOCOL, OtlpConfig.Protocol.class, OtlpConfig.Protocol.HTTP_PROTOBUF); - otlpMetricsTimeout = - configProvider.getInteger( - OTLP_METRICS_TIMEOUT, Math.min(metricsOtelTimeout, DEFAULT_METRICS_OTEL_TIMEOUT)); String otlpMetricsEndpointFromEnvironment = configProvider.getString(OTLP_METRICS_ENDPOINT); if (otlpMetricsEndpointFromEnvironment == null) { diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 866d628dd13..622d44d5fb6 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -452,12 +452,12 @@ class ConfigTest extends DDSpecification { then: !config.metricsOtelEnabled - config.metricsOtelInterval == -1 + config.metricsOtelInterval == 10000 config.metricsOtelTimeout == 7500 config.otlpMetricsEndpoint == "invalid" config.otlpMetricsHeaders == [:] config.otlpMetricsProtocol == HTTP_PROTOBUF - config.otlpMetricsTimeout == -34 + config.otlpMetricsTimeout == 7500 config.otlpMetricsTemporalityPreference == DELTA } diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java index b6d06f11706..d8b12c81280 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java @@ -232,10 +232,12 @@ private String getOtelOtlpProperty(String signal, String subkey, String ddSysPro String otelKey = "otel.exporter.otlp." + signal + "." + subkey; String otelValue = getOtelProperty(otelKey); if (null == otelValue) { + // fall back to general configuration otelKey = "otel.exporter.otlp." + subkey; otelValue = getOtelProperty(otelKey); - // special case when using general endpoint as fallback: append relevant metric endpoint - if ("endpoint".equals(subkey) + // special case when using general endpoint as fallback: append appropriate metric suffix + if ("metrics".equals(signal) + && "endpoint".equals(subkey) && otelValue != null && !"grpc".equalsIgnoreCase(otelEnvironment.get(OTLP_METRICS_PROTOCOL))) { otelValue = otelValue + "/v1/metrics";