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..6c9633fc543 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 @@ -15,6 +15,8 @@ public final class OtlpConfig { public static final String OTLP_METRICS_TEMPORALITY_PREFERENCE = "otlp.metrics.temporality.preference"; + public static final String TRACE_OTEL_EXPORTER = "trace.otel.exporter"; + public enum Protocol { GRPC, HTTP_PROTOBUF, 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..fd36a0a6a8f 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -455,6 +455,7 @@ 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.TRACE_OTEL_EXPORTER; 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,6 +914,8 @@ public static String getHostName() { private final boolean jmxFetchMultipleRuntimeServicesEnabled; private final int jmxFetchMultipleRuntimeServicesLimit; + private final String traceOtelExporter; + private final boolean metricsOtelEnabled; private final int metricsOtelInterval; private final int metricsOtelTimeout; @@ -1889,6 +1892,8 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins statsDClientSocketBuffer = configProvider.getInteger(STATSD_CLIENT_SOCKET_BUFFER); statsDClientSocketTimeout = configProvider.getInteger(STATSD_CLIENT_SOCKET_TIMEOUT); + traceOtelExporter = configProvider.getString(TRACE_OTEL_EXPORTER); + metricsOtelEnabled = configProvider.getBoolean(METRICS_OTEL_ENABLED, DEFAULT_METRICS_OTEL_ENABLED); @@ -5204,6 +5209,10 @@ public boolean isJmxFetchIntegrationEnabled( return configProvider.isEnabled(integrationNames, "jmxfetch.", ".enabled", defaultEnabled); } + public boolean isOtlpTracesExporterEnabled() { + return "otlp".equalsIgnoreCase(traceOtelExporter); + } + public boolean isMetricsOtelEnabled() { return metricsOtelEnabled; } @@ -6255,6 +6264,9 @@ public String toString() { + aiGuardEnabled + ", aiGuardEndpoint=" + aiGuardEndpoint + + ", traceOtelExporter='" + + traceOtelExporter + + '\'' + ", metricsOtelEnabled=" + metricsOtelEnabled + ", metricsOtelInterval=" diff --git a/internal-api/src/test/groovy/datadog/trace/api/telemetry/OtelEnvMetricCollectorImplTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/telemetry/OtelEnvMetricCollectorImplTest.groovy index 6364482fb75..df44fe16d02 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/telemetry/OtelEnvMetricCollectorImplTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/telemetry/OtelEnvMetricCollectorImplTest.groovy @@ -199,7 +199,7 @@ class OtelEnvMetricCollectorImplTest extends DDSpecification { where: otelEnvKey | otelEnvValue || metricType | metricValue | metricNamespace | metricName | tagsOtelValue 'OTEL_METRICS_EXPORTER' | 'otlp' || 'count' | 1 | 'tracers' | 'otel.env.unsupported' | 'config_opentelemetry:otel_metrics_exporter' - 'OTEL_TRACES_EXPORTER' | 'otlp' || 'count' | 1 | 'tracers' | 'otel.env.unsupported' | 'config_opentelemetry:otel_traces_exporter' + 'OTEL_TRACES_EXPORTER' | 'zipkin' || 'count' | 1 | 'tracers' | 'otel.env.unsupported' | 'config_opentelemetry:otel_traces_exporter' 'OTEL_LOGS_EXPORTER' | 'otlp' || 'count' | 1 | 'tracers' | 'otel.env.unsupported' | 'config_opentelemetry:otel_logs_exporter' } } 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..491abb39dcf 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,6 +9,7 @@ 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_EXPORTER 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 @@ -231,6 +232,44 @@ class OtelEnvironmentConfigSourceTest extends DDSpecification { source.get(TRACE_EXTENSIONS_PATH) == '/opt/opentelemetry/extensions' } + def "otel traces exporter otlp system property is mapped"() { + setup: + injectSysConfig('dd.trace.otel.enabled', 'true', false) + injectSysConfig('otel.traces.exporter', 'otlp', false) + + when: + def source = new OtelEnvironmentConfigSource() + + then: + source.get(TRACE_ENABLED) == null + source.get(TRACE_OTEL_EXPORTER) == 'otlp' + } + + def "otel traces exporter otlp environment variable is mapped"() { + setup: + injectEnvConfig('DD_TRACE_OTEL_ENABLED', 'true', false) + injectEnvConfig('OTEL_TRACES_EXPORTER', 'otlp', false) + + when: + def source = new OtelEnvironmentConfigSource() + + then: + source.get(TRACE_ENABLED) == null + source.get(TRACE_OTEL_EXPORTER) == 'otlp' + } + + def "otel traces exporter none still disables tracing"() { + setup: + injectEnvConfig('DD_TRACE_OTEL_ENABLED', 'true', false) + injectEnvConfig('OTEL_TRACES_EXPORTER', 'none', false) + + when: + def source = new OtelEnvironmentConfigSource() + + then: + source.get(TRACE_ENABLED) == 'false' + } + def "otel resource attributes system property is mapped"() { setup: injectSysConfig('dd.trace.otel.enabled', 'true', false) 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..01e767bfb67 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,6 +18,7 @@ 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.TRACE_OTEL_EXPORTER; 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; @@ -134,11 +135,20 @@ private void setupTraceOtelEnvironment() { capture(TRACE_PROPAGATION_STYLE, mapPropagationStyle(propagators)); capture(TRACE_SAMPLE_RATE, mapSampleRate(tracesSampler)); capture(TRACE_ENABLED, mapDataCollection("traces")); + capture(TRACE_OTEL_EXPORTER, mapTracesExporter()); capture(REQUEST_HEADER_TAGS, mapHeaderTags("http.request.header.", requestHeaders)); capture(RESPONSE_HEADER_TAGS, mapHeaderTags("http.response.header.", responseHeaders)); capture(TRACE_EXTENSIONS_PATH, extensions); } + private String mapTracesExporter() { + String exporter = getOtelProperty("otel.traces.exporter"); + if ("otlp".equalsIgnoreCase(exporter)) { + return "otlp"; + } + return null; + } + private void setupMetricsOtelEnvironment() { capture( METRICS_OTEL_INTERVAL, @@ -439,7 +449,11 @@ private String mapDataCollection(String signal) { } if ("none".equalsIgnoreCase(exporter)) { - return "false"; // currently we only accept "none" which maps to disable data collection + return "false"; // "none" maps to disable data collection + } + + if ("traces".equals(signal) && "otlp".equalsIgnoreCase(exporter)) { + return null; // otlp is handled separately for traces } log.warn("OTEL_{}_EXPORTER={} is not supported", signal, exporter.toUpperCase(Locale.ROOT));