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 9fa15e8f241..465812e7f7b 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,7 +109,10 @@ public final class ConfigDefaults { static final int DEFAULT_METRICS_OTEL_TIMEOUT = 7_500; // ms static final int DEFAULT_METRICS_OTEL_CARDINALITY_LIMIT = 2_000; - static final String DEFAULT_OTLP_HTTP_METRIC_ENDPOINT = "v1/metrics"; + static final int DEFAULT_OTLP_TRACES_TIMEOUT = 10_000; // ms + + static final String DEFAULT_OTLP_HTTP_METRICS_ENDPOINT = "v1/metrics"; + static final String DEFAULT_OTLP_HTTP_TRACES_ENDPOINT = "v1/traces"; static final String DEFAULT_OTLP_HTTP_PORT = "4318"; static final String DEFAULT_OTLP_GRPC_PORT = "4317"; 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 de266aafc24..e6c28b338fd 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 @@ -32,5 +32,12 @@ public enum Temporality { LOWMEMORY } + public static final String TRACE_OTEL_ENABLED = "trace.otel.enabled"; + public static final String OTLP_TRACES_ENDPOINT = "otlp.traces.endpoint"; + public static final String OTLP_TRACES_HEADERS = "otlp.traces.headers"; + public static final String OTLP_TRACES_PROTOCOL = "otlp.traces.protocol"; + public static final String OTLP_TRACES_COMPRESSION = "otlp.traces.compression"; + public static final String OTLP_TRACES_TIMEOUT = "otlp.traces.timeout"; + private OtlpConfig() {} } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java index 092d97cea5a..cf4fbb1d78f 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java @@ -12,7 +12,6 @@ public final class TraceInstrumentationConfig { public static final String CODE_ORIGIN_FOR_SPANS_ENABLED = "code.origin.for.spans.enabled"; public static final String CODE_ORIGIN_MAX_USER_FRAMES = "code.origin.max.user.frames"; public static final String TRACE_ENABLED = "trace.enabled"; - public static final String TRACE_OTEL_ENABLED = "trace.otel.enabled"; public static final String INTEGRATIONS_ENABLED = "integrations.enabled"; public static final String TRACE_EXTENSIONS_PATH = "trace.extensions.path"; 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 6028754ce04..95f191f5d8a 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -112,12 +112,13 @@ 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_CARDINALITY_LIMIT; -import static datadog.trace.api.ConfigDefaults.DEFAULT_METRICS_OTEL_ENABLED; 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_METRICS_ENDPOINT; import static datadog.trace.api.ConfigDefaults.DEFAULT_OTLP_HTTP_PORT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTLP_HTTP_TRACES_ENDPOINT; +import static datadog.trace.api.ConfigDefaults.DEFAULT_OTLP_TRACES_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; @@ -446,7 +447,6 @@ 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_CARDINALITY_LIMIT; -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_COMPRESSION; @@ -455,6 +455,11 @@ 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_TRACES_COMPRESSION; +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_ENDPOINT; +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_HEADERS; +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_PROTOCOL; +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_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; @@ -913,7 +918,6 @@ public static String getHostName() { private final boolean jmxFetchMultipleRuntimeServicesEnabled; private final int jmxFetchMultipleRuntimeServicesLimit; - private final boolean metricsOtelEnabled; private final int metricsOtelInterval; private final int metricsOtelTimeout; private final int metricsOtelCardinalityLimit; @@ -924,6 +928,12 @@ public static String getHostName() { private final int otlpMetricsTimeout; private final OtlpConfig.Temporality otlpMetricsTemporalityPreference; + private final String otlpTracesEndpoint; + private final Map otlpTracesHeaders; + private final OtlpConfig.Protocol otlpTracesProtocol; + private final OtlpConfig.Compression otlpTracesCompression; + private final int otlpTracesTimeout; + // These values are default-ed to those of jmx fetch values as needed private final boolean healthMetricsEnabled; private final String healthMetricsStatsdHost; @@ -1889,9 +1899,6 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins statsDClientSocketBuffer = configProvider.getInteger(STATSD_CLIENT_SOCKET_BUFFER); statsDClientSocketTimeout = configProvider.getInteger(STATSD_CLIENT_SOCKET_TIMEOUT); - metricsOtelEnabled = - configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED); - int cardinalityLimit = configProvider.getInteger( METRICS_OTEL_CARDINALITY_LIMIT, DEFAULT_METRICS_OTEL_CARDINALITY_LIMIT); @@ -1919,11 +1926,11 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins 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); + int defaultOtlpMetricsTimeout = Math.min(metricsOtelTimeout, DEFAULT_METRICS_OTEL_TIMEOUT); + int otlpTimeout = configProvider.getInteger(OTLP_METRICS_TIMEOUT, defaultOtlpMetricsTimeout); if (otlpTimeout < 0) { log.warn("Invalid OTLP metrics timeout: {}. The value must be positive", otlpTimeout); - otlpTimeout = defaultOtlpTimeout; + otlpTimeout = defaultOtlpMetricsTimeout; } otlpMetricsTimeout = otlpTimeout; @@ -1946,7 +1953,7 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins + ':' + DEFAULT_OTLP_HTTP_PORT + '/' - + DEFAULT_OTLP_HTTP_METRIC_ENDPOINT; + + DEFAULT_OTLP_HTTP_METRICS_ENDPOINT; } } otlpMetricsEndpoint = otlpMetricsEndpointFromEnvironment; @@ -1957,6 +1964,37 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins OtlpConfig.Temporality.class, OtlpConfig.Temporality.DELTA); + otlpTimeout = configProvider.getInteger(OTLP_TRACES_TIMEOUT, DEFAULT_OTLP_TRACES_TIMEOUT); + if (otlpTimeout < 0) { + log.warn("Invalid OTLP traces timeout: {}. The value must be positive", otlpTimeout); + otlpTimeout = DEFAULT_METRICS_OTEL_TIMEOUT; + } + otlpTracesTimeout = otlpTimeout; + + otlpTracesHeaders = configProvider.getMergedMap(OTLP_TRACES_HEADERS, '='); + otlpTracesProtocol = + configProvider.getEnum( + OTLP_TRACES_PROTOCOL, OtlpConfig.Protocol.class, OtlpConfig.Protocol.HTTP_PROTOBUF); + otlpTracesCompression = + configProvider.getEnum( + OTLP_TRACES_COMPRESSION, OtlpConfig.Compression.class, OtlpConfig.Compression.NONE); + + String otlpTracesEndpointFromEnvironment = configProvider.getString(OTLP_TRACES_ENDPOINT); + if (otlpTracesEndpointFromEnvironment == null) { + if (otlpMetricsProtocol == OtlpConfig.Protocol.GRPC) { + otlpTracesEndpointFromEnvironment = "http://" + agentHost + ':' + DEFAULT_OTLP_GRPC_PORT; + } else { + otlpTracesEndpointFromEnvironment = + "http://" + + agentHost + + ':' + + DEFAULT_OTLP_HTTP_PORT + + '/' + + DEFAULT_OTLP_HTTP_TRACES_ENDPOINT; + } + } + otlpTracesEndpoint = otlpTracesEndpointFromEnvironment; + // Runtime metrics are disabled if Otel metrics are enabled and the metrics exporter is none runtimeMetricsEnabled = configProvider.getBoolean(RUNTIME_METRICS_ENABLED, true); @@ -5205,7 +5243,7 @@ public boolean isJmxFetchIntegrationEnabled( } public boolean isMetricsOtelEnabled() { - return metricsOtelEnabled; + return instrumenterConfig.isMetricsOtelEnabled(); } public int getMetricsOtelCardinalityLimit() { @@ -5244,6 +5282,30 @@ public OtlpConfig.Temporality getOtlpMetricsTemporalityPreference() { return otlpMetricsTemporalityPreference; } + public boolean isTraceOtelEnabled() { + return instrumenterConfig.isTraceOtelEnabled(); + } + + public String getOtlpTracesEndpoint() { + return otlpTracesEndpoint; + } + + public Map getOtlpTracesHeaders() { + return otlpTracesHeaders; + } + + public OtlpConfig.Protocol getOtlpTracesProtocol() { + return otlpTracesProtocol; + } + + public OtlpConfig.Compression getOtlpTracesCompression() { + return otlpTracesCompression; + } + + public int getOtlpTracesTimeout() { + return otlpTracesTimeout; + } + public boolean isRuleEnabled(final String name) { return isRuleEnabled(name, true); } @@ -6255,8 +6317,6 @@ public String toString() { + aiGuardEnabled + ", aiGuardEndpoint=" + aiGuardEndpoint - + ", metricsOtelEnabled=" - + metricsOtelEnabled + ", metricsOtelInterval=" + metricsOtelInterval + ", metricsOtelTimeout=" @@ -6275,6 +6335,16 @@ public String toString() { + otlpMetricsTimeout + ", otlpMetricsTemporalityPreference=" + otlpMetricsTemporalityPreference + + ", otlpTracesEndpoint=" + + otlpTracesEndpoint + + ", otlpTracesHeaders=" + + otlpTracesHeaders + + ", otlpTracesProtocol=" + + otlpTracesProtocol + + ", otlpTracesCompression=" + + otlpTracesCompression + + ", otlpTracesTimeout=" + + otlpTracesTimeout + ", serviceDiscoveryEnabled=" + serviceDiscoveryEnabled + ", sfnInjectDatadogAttributeEnabled=" diff --git a/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java b/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java index 8097cf4726b..00dd43f7197 100644 --- a/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java +++ b/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java @@ -39,6 +39,7 @@ import static datadog.trace.api.config.IastConfig.IAST_ENABLED; import static datadog.trace.api.config.LlmObsConfig.LLMOBS_ENABLED; import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED; +import static datadog.trace.api.config.OtlpConfig.TRACE_OTEL_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_ENABLED; @@ -80,7 +81,6 @@ import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_EXECUTORS_ALL; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_EXTENSIONS_PATH; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_METHODS; -import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_OTEL_ENABLED; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_PEKKO_SCHEDULER_ENABLED; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_THREAD_POOL_EXECUTORS_EXCLUDE; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_WEBSOCKET_MESSAGES_ENABLED; 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 e32b35777d4..fde84e0ff38 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -144,6 +144,11 @@ 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_TIMEOUT import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_TEMPORALITY_PREFERENCE +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_ENDPOINT +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_HEADERS +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_PROTOCOL +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_TIMEOUT +import static datadog.trace.api.config.OtlpConfig.TRACE_OTEL_ENABLED import datadog.trace.config.inversion.ConfigHelper import datadog.trace.api.env.FixedCapturedEnvironment @@ -231,6 +236,15 @@ class ConfigTest extends DDSpecification { 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" + private static final OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_ENV = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" + private static final OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_PROP = "otel.exporter.otlp.traces.endpoint" + private static final OTEL_EXPORTER_OTLP_TRACES_HEADERS_ENV = "OTEL_EXPORTER_OTLP_TRACES_HEADERS" + private static final OTEL_EXPORTER_OTLP_TRACES_HEADERS_PROP = "otel.exporter.otlp.traces.headers" + private static final OTEL_EXPORTER_OTLP_TRACES_PROTOCOL_ENV = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL" + private static final OTEL_EXPORTER_OTLP_TRACES_PROTOCOL_PROP = "otel.exporter.otlp.traces.protocol" + private static final OTEL_EXPORTER_OTLP_TRACES_TIMEOUT_ENV = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT" + private static final OTEL_EXPORTER_OTLP_TRACES_TIMEOUT_PROP = "otel.exporter.otlp.traces.timeout" + def setup() { FixedCapturedEnvironment.useFixedEnv([:]) } @@ -340,11 +354,17 @@ class ConfigTest extends DDSpecification { prop.setProperty(METRICS_OTEL_INTERVAL, "11000") prop.setProperty(METRICS_OTEL_TIMEOUT, "9000") 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_HEADERS, "api-key=key,other-config-value=value,metrics-config-value=M") prop.setProperty(OTLP_METRICS_PROTOCOL, "http/protobuf") - prop.setProperty(OTLP_METRICS_TIMEOUT, "5000") + prop.setProperty(OTLP_METRICS_TIMEOUT, "5001") prop.setProperty(OTLP_METRICS_TEMPORALITY_PREFERENCE, "cumulative") + prop.setProperty(TRACE_OTEL_ENABLED, "True") + prop.setProperty(OTLP_TRACES_ENDPOINT, "http://localhost:4333/v1/traces") + prop.setProperty(OTLP_TRACES_HEADERS, "api-key=key,other-config-value=value,traces-config-value=T") + prop.setProperty(OTLP_TRACES_PROTOCOL, "http/protobuf") + prop.setProperty(OTLP_TRACES_TIMEOUT, "5002") + when: Config config = Config.get(prop) @@ -450,18 +470,28 @@ class ConfigTest extends DDSpecification { !config.isEventbridgeInjectDatadogAttributeEnabled() config.xDatadogTagsMaxLength == 128 + config.metricsOtelEnabled config.metricsOtelInterval == 11000 config.metricsOtelTimeout == 9000 config.otlpMetricsEndpoint == "http://localhost:4333/v1/metrics" config.otlpMetricsHeaders["api-key"] == "key" config.otlpMetricsHeaders["other-config-value"] == "value" + config.otlpMetricsHeaders["metrics-config-value"] == "M" config.otlpMetricsProtocol == HTTP_PROTOBUF - config.otlpMetricsTimeout == 5000 + config.otlpMetricsTimeout == 5001 config.otlpMetricsTemporalityPreference == CUMULATIVE + + config.traceOtelEnabled + config.otlpTracesEndpoint == "http://localhost:4333/v1/traces" + config.otlpTracesHeaders["api-key"] == "key" + config.otlpTracesHeaders["other-config-value"] == "value" + config.otlpTracesHeaders["traces-config-value"] == "T" + config.otlpTracesProtocol == HTTP_PROTOBUF + config.otlpTracesTimeout == 5002 } - def "otel metrics: default values when configured incorrectly"() { + def "otel: default values when configured incorrectly"() { setup: def prop = new Properties() @@ -474,6 +504,12 @@ class ConfigTest extends DDSpecification { prop.setProperty(OTLP_METRICS_TIMEOUT, "-34") prop.setProperty(OTLP_METRICS_TEMPORALITY_PREFERENCE, "invalid") + prop.setProperty(TRACE_OTEL_ENABLED, "youhou") + prop.setProperty(OTLP_TRACES_ENDPOINT, "invalid") + prop.setProperty(OTLP_TRACES_HEADERS, "11") + prop.setProperty(OTLP_TRACES_PROTOCOL, "invalid") + prop.setProperty(OTLP_TRACES_TIMEOUT, "-34") + when: Config config = Config.get(prop) @@ -486,9 +522,15 @@ class ConfigTest extends DDSpecification { config.otlpMetricsProtocol == HTTP_PROTOBUF config.otlpMetricsTimeout == 7500 config.otlpMetricsTemporalityPreference == DELTA + + !config.traceOtelEnabled + config.otlpTracesEndpoint == "invalid" + config.otlpTracesHeaders == [:] + config.otlpTracesProtocol == HTTP_PROTOBUF + config.otlpTracesTimeout == 7500 } - def "otel metrics: default values when not set"() { + def "otel: default values when not set"() { setup: def prop = new Properties() @@ -504,19 +546,26 @@ class ConfigTest extends DDSpecification { config.otlpMetricsProtocol == HTTP_PROTOBUF config.otlpMetricsTimeout == 7500 config.otlpMetricsTemporalityPreference == DELTA - } + !config.traceOtelEnabled + config.otlpTracesEndpoint == "http://localhost:4318/v1/traces" + config.otlpTracesHeaders == [:] + config.otlpTracesProtocol == HTTP_PROTOBUF + config.otlpTracesTimeout == 7500 + } - def "otel metrics: check syntax for attributes and headers"() { + def "otel: check syntax for OTLP headers"() { setup: def prop = new Properties() prop.setProperty(OTLP_METRICS_HEADERS, "api,key=key") + prop.setProperty(OTLP_TRACES_HEADERS, "api,key=key") when: Config config = Config.get(prop) then: config.otlpMetricsHeaders.size() == 0 + config.otlpTracesHeaders.size() == 0 } def "otel generic config via system properties - metrics enabled"() { @@ -559,7 +608,6 @@ class ConfigTest extends DDSpecification { config.logLevel == "warning" } - def "otel generic config via env var - metrics enabled"() { setup: environmentVariables.set(DD_METRICS_OTEL_ENABLED_ENV, "true") @@ -598,9 +646,10 @@ class ConfigTest extends DDSpecification { config.logLevel == "error" } - def "otel metrics: fallback keys"() { + def "otel: OTLP fallback keys"() { setup: System.setProperty(DD_METRICS_OTEL_ENABLED_PROP, "true") + System.setProperty(DD_TRACE_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") @@ -616,11 +665,19 @@ class ConfigTest extends DDSpecification { config.otlpMetricsHeaders["api-key"] == "key" config.otlpMetricsHeaders["other-config-value"] == "value" config.otlpMetricsTimeout == 1000 + + config.otlpTracesProtocol == HTTP_JSON + config.otlpTracesEndpoint == "http://localhost:4319/v1/traces" + config.otlpTracesHeaders.size() == 2 + config.otlpTracesHeaders["api-key"] == "key" + config.otlpTracesHeaders["other-config-value"] == "value" + config.otlpTracesTimeout == 1000 } - def "otel metrics: fallback key endpoint"() { + def "otel: OTLP fallback key endpoint"() { setup: System.setProperty(DD_METRICS_OTEL_ENABLED_PROP, "true") + System.setProperty(DD_TRACE_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") @@ -631,11 +688,14 @@ class ConfigTest extends DDSpecification { config.agentHost == "192.168.0.3" config.otlpMetricsProtocol == HTTP_JSON config.otlpMetricsEndpoint == "http://192.168.0.3:4318/v1/metrics" + config.otlpTracesProtocol == HTTP_JSON + config.otlpTracesEndpoint == "http://192.168.0.3:4318/v1/traces" } - def "otel metrics: fallback key endpoint 2"() { + def "otel: OTLP fallback key endpoint 2"() { setup: System.setProperty(DD_METRICS_OTEL_ENABLED_PROP, "true") + System.setProperty(DD_TRACE_OTEL_ENABLED_PROP, "true") System.setProperty(PREFIX + TRACE_AGENT_URL,"'/tmp/ddagent/trace.sock'") when: @@ -645,6 +705,8 @@ class ConfigTest extends DDSpecification { config.agentHost == "localhost" config.otlpMetricsProtocol == HTTP_PROTOBUF config.otlpMetricsEndpoint == "http://localhost:4318/v1/metrics" + config.otlpTracesProtocol == HTTP_PROTOBUF + config.otlpTracesEndpoint == "http://localhost:4318/v1/traces" } @@ -751,10 +813,15 @@ class ConfigTest extends DDSpecification { 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_HEADERS_PROP, "api-key=key,other-config-value=value,metrics-config-value=M") System.setProperty(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL_PROP, "http/protobuf") - System.setProperty(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT_PROP, "5000") + System.setProperty(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT_PROP, "5001") System.setProperty(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE_PROP, "cumulative") + System.setProperty(DD_TRACE_OTEL_ENABLED_PROP, "True") + System.setProperty(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_PROP, "http://localhost:4333/v1/traces") + System.setProperty(OTEL_EXPORTER_OTLP_TRACES_HEADERS_PROP, "api-key=key,other-config-value=value,traces-config-value=T") + System.setProperty(OTEL_EXPORTER_OTLP_TRACES_PROTOCOL_PROP, "http/protobuf") + System.setProperty(OTEL_EXPORTER_OTLP_TRACES_TIMEOUT_PROP, "5002") System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production") when: @@ -866,9 +933,18 @@ class ConfigTest extends DDSpecification { config.otlpMetricsEndpoint == "http://localhost:4333/v1/metrics" config.otlpMetricsHeaders["api-key"] == "key" config.otlpMetricsHeaders["other-config-value"] == "value" + config.otlpMetricsHeaders["metrics-config-value"] == "M" config.otlpMetricsProtocol == HTTP_PROTOBUF - config.otlpMetricsTimeout == 5000 + config.otlpMetricsTimeout == 5001 config.otlpMetricsTemporalityPreference == CUMULATIVE + + config.traceOtelEnabled + config.otlpTracesEndpoint == "http://localhost:4333/v1/traces" + config.otlpTracesHeaders["api-key"] == "key" + config.otlpTracesHeaders["other-config-value"] == "value" + config.otlpTracesHeaders["traces-config-value"] == "T" + config.otlpTracesProtocol == HTTP_PROTOBUF + config.otlpTracesTimeout == 5002 } def "specify overrides via env vars"() { @@ -899,10 +975,15 @@ class ConfigTest extends DDSpecification { 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_HEADERS_ENV, "api-key=key,other-config-value=value,metrics-config-value=M") 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_TIMEOUT_ENV, "5001") environmentVariables.set(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE_ENV, "cumulative") + environmentVariables.set(DD_TRACE_OTEL_ENABLED_ENV, "True") + environmentVariables.set(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_ENV, "http://localhost:4333/v1/traces") + environmentVariables.set(OTEL_EXPORTER_OTLP_TRACES_HEADERS_ENV, "api-key=key,other-config-value=value,traces-config-value=T") + environmentVariables.set(OTEL_EXPORTER_OTLP_TRACES_PROTOCOL_ENV, "http/protobuf") + environmentVariables.set(OTEL_EXPORTER_OTLP_TRACES_TIMEOUT_ENV, "5002") when: def config = new Config() @@ -931,15 +1012,25 @@ class ConfigTest extends DDSpecification { config.requestHeaderTags == ["*": "http.request.headers."] config.responseHeaderTags == ["*": "http.response.headers."] + config.metricsOtelEnabled config.metricsOtelInterval == 11000 config.metricsOtelTimeout == 9000 config.otlpMetricsEndpoint == "http://localhost:4333/v1/metrics" config.otlpMetricsHeaders["api-key"] == "key" config.otlpMetricsHeaders["other-config-value"] == "value" + config.otlpMetricsHeaders["metrics-config-value"] == "M" config.otlpMetricsProtocol == HTTP_PROTOBUF - config.otlpMetricsTimeout == 5000 + config.otlpMetricsTimeout == 5001 config.otlpMetricsTemporalityPreference == CUMULATIVE + + config.traceOtelEnabled + config.otlpTracesEndpoint == "http://localhost:4333/v1/traces" + config.otlpTracesHeaders["api-key"] == "key" + config.otlpTracesHeaders["other-config-value"] == "value" + config.otlpTracesHeaders["traces-config-value"] == "T" + config.otlpTracesProtocol == HTTP_PROTOBUF + config.otlpTracesTimeout == 5002 } def "sys props override env vars"() { diff --git a/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSourceTest.groovy b/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSourceTest.groovy index 25b55d2518b..f8b85a55bda 100644 --- a/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSourceTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSourceTest.groovy @@ -9,9 +9,9 @@ import static datadog.trace.api.config.GeneralConfig.RUNTIME_METRICS_ENABLED 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.OtlpConfig.TRACE_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 import static datadog.trace.api.config.TracerConfig.REQUEST_HEADER_TAGS import static datadog.trace.api.config.TracerConfig.RESPONSE_HEADER_TAGS import static datadog.trace.api.config.TracerConfig.TRACE_PROPAGATION_STYLE diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index 9928be865b6..a8070047b9d 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -2337,6 +2337,46 @@ "aliases": [] } ], + "DD_OTLP_TRACES_ENDPOINT": [ + { + "version": "A", + "type": "string", + "default": null, + "aliases": [] + } + ], + "DD_OTLP_TRACES_HEADERS": [ + { + "version": "A", + "type": "map", + "default": null, + "aliases": [] + } + ], + "DD_OTLP_TRACES_PROTOCOL": [ + { + "version": "A", + "type": "string", + "default": "HTTP_PROTOBUF", + "aliases": [] + } + ], + "DD_OTLP_TRACES_COMPRESSION": [ + { + "version": "A", + "type": "string", + "default": "NONE", + "aliases": [] + } + ], + "DD_OTLP_TRACES_TIMEOUT": [ + { + "version": "A", + "type": "int", + "default": "10000", + "aliases": [] + } + ], "DD_PIPELINE_EXECUTION_ID": [ { "version": "A", @@ -11161,6 +11201,46 @@ "aliases": [] } ], + "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": [ + { + "version": "A", + "type": "string", + "default": null, + "aliases": [] + } + ], + "OTEL_EXPORTER_OTLP_TRACES_HEADERS": [ + { + "version": "A", + "type": "string", + "default": null, + "aliases": [] + } + ], + "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL": [ + { + "version": "A", + "type": "string", + "default": null, + "aliases": [] + } + ], + "OTEL_EXPORTER_OTLP_TRACES_COMPRESSION": [ + { + "version": "A", + "type": "string", + "default": null, + "aliases": [] + } + ], + "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT": [ + { + "version": "A", + "type": "int", + "default": "10000", + "aliases": [] + } + ], "DD_LEGACY_CONTEXT_MANAGER_ENABLED": [ { "version": "A", 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 2bcf9f414f0..fb1808c8916 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 @@ -18,9 +18,14 @@ 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_TRACES_COMPRESSION; +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_ENDPOINT; +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_HEADERS; +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_PROTOCOL; +import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_TIMEOUT; +import static datadog.trace.api.config.OtlpConfig.TRACE_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; import static datadog.trace.api.config.TracerConfig.REQUEST_HEADER_TAGS; import static datadog.trace.api.config.TracerConfig.RESPONSE_HEADER_TAGS; import static datadog.trace.api.config.TracerConfig.TRACE_PROPAGATION_STYLE; @@ -137,6 +142,25 @@ private void setupTraceOtelEnvironment() { capture(REQUEST_HEADER_TAGS, mapHeaderTags("http.request.header.", requestHeaders)); capture(RESPONSE_HEADER_TAGS, mapHeaderTags("http.response.header.", responseHeaders)); capture(TRACE_EXTENSIONS_PATH, extensions); + + String exporter = getOtelProperty("otel.traces.exporter"); + if (exporter == null || "otlp".equalsIgnoreCase(exporter)) { + capture( + OTLP_TRACES_HEADERS, + getOtelOtlpProperty("traces", "headers", "dd." + OTLP_TRACES_HEADERS)); + capture( + OTLP_TRACES_PROTOCOL, + getOtelOtlpProperty("traces", "protocol", "dd." + OTLP_TRACES_PROTOCOL)); + capture( + OTLP_TRACES_COMPRESSION, + getOtelOtlpProperty("traces", "compression", "dd." + OTLP_TRACES_COMPRESSION)); + capture( + OTLP_TRACES_TIMEOUT, + getOtelOtlpProperty("traces", "timeout", "dd." + OTLP_TRACES_TIMEOUT)); + capture( + OTLP_TRACES_ENDPOINT, + getOtelOtlpProperty("traces", "endpoint", "dd." + OTLP_TRACES_ENDPOINT)); + } } private void setupMetricsOtelEnvironment() { @@ -244,12 +268,16 @@ private String getOtelOtlpProperty(String signal, String subkey, String ddSysPro // fall back to general configuration otelKey = "otel.exporter.otlp." + subkey; otelValue = getOtelProperty(otelKey); - // 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"; + // special case when using general endpoint as fallback: append appropriate suffix + if ("endpoint".equals(subkey) && otelValue != null) { + if ("metrics".equals(signal) + && !"grpc".equalsIgnoreCase(otelEnvironment.get(OTLP_METRICS_PROTOCOL))) { + otelValue = otelValue + "/v1/metrics"; + } + if ("traces".equals(signal) + && !"grpc".equalsIgnoreCase(otelEnvironment.get(OTLP_TRACES_PROTOCOL))) { + otelValue = otelValue + "/v1/traces"; + } } } if (null == otelValue) {