Skip to content

Commit 29af0b4

Browse files
mhlidddevflow.devflow-routing-intake
andauthored
Add OTLP Trace Metrics Configs (#11653)
init adding tests Merge branch 'master' into mhlidd/otlp_trace_metrics_config bugfix fixing issue where internal DD configs are used instead of OTel equivalents Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
1 parent 16a5297 commit 29af0b4

8 files changed

Lines changed: 167 additions & 0 deletions

File tree

dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ public final class ConfigDefaults {
115115
static final int DEFAULT_METRICS_OTEL_TIMEOUT = 7_500; // ms
116116
static final int DEFAULT_METRICS_OTEL_CARDINALITY_LIMIT = 2_000;
117117

118+
static final int DEFAULT_TRACE_STATS_INTERVAL = 10_000; // ms
119+
118120
public static final boolean DEFAULT_METRICS_OTEL_EXPERIMENTAL_ENABLED = true;
119121

120122
public static final int DEFAULT_OTLP_TRACES_TIMEOUT = 10_000; // ms

dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ public final class GeneralConfig {
6969
public static final String TRACE_STATS_COMPUTATION_ENABLED = "trace.stats.computation.enabled";
7070
public static final String TRACE_STATS_COMPUTATION_IGNORE_AGENT_VERSION =
7171
"trace.stats.computation.ignore.agent.version";
72+
73+
public static final String TRACE_OTEL_SEMANTICS_ENABLED = "trace.otel.semantics.enabled";
74+
7275
public static final String TRACER_METRICS_ENABLED = "trace.tracer.metrics.enabled";
7376
public static final String TRACER_METRICS_BUFFERING_ENABLED =
7477
"trace.tracer.metrics.buffering.enabled";

dd-trace-api/src/main/java/datadog/trace/api/config/OtlpConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public final class OtlpConfig {
3131
public static final String OTLP_METRICS_TEMPORALITY_PREFERENCE =
3232
"otlp.metrics.temporality.preference";
3333

34+
public static final String TRACES_SPAN_METRICS_ENABLED = "traces.span.metrics.enabled";
35+
3436
public static final String TRACE_OTEL_ENABLED = "trace.otel.enabled";
3537
public static final String TRACE_OTEL_EXPORTER = "trace.otel.exporter";
3638

internal-api/src/main/java/datadog/trace/api/Config.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@
186186
import static datadog.trace.api.ConfigDefaults.DEFAULT_TRACE_RATE_LIMIT;
187187
import static datadog.trace.api.ConfigDefaults.DEFAULT_TRACE_REPORT_HOSTNAME;
188188
import static datadog.trace.api.ConfigDefaults.DEFAULT_TRACE_RESOLVER_ENABLED;
189+
import static datadog.trace.api.ConfigDefaults.DEFAULT_TRACE_STATS_INTERVAL;
189190
import static datadog.trace.api.ConfigDefaults.DEFAULT_TRACE_X_DATADOG_TAGS_MAX_LENGTH;
190191
import static datadog.trace.api.ConfigDefaults.DEFAULT_WEBSOCKET_MESSAGES_INHERIT_SAMPLING;
191192
import static datadog.trace.api.ConfigDefaults.DEFAULT_WEBSOCKET_MESSAGES_SEPARATE_TRACES;
@@ -418,6 +419,7 @@
418419
import static datadog.trace.api.config.GeneralConfig.TRACER_METRICS_MAX_PENDING;
419420
import static datadog.trace.api.config.GeneralConfig.TRACE_DEBUG;
420421
import static datadog.trace.api.config.GeneralConfig.TRACE_LOG_LEVEL;
422+
import static datadog.trace.api.config.GeneralConfig.TRACE_OTEL_SEMANTICS_ENABLED;
421423
import static datadog.trace.api.config.GeneralConfig.TRACE_STATS_COMPUTATION_ENABLED;
422424
import static datadog.trace.api.config.GeneralConfig.TRACE_STATS_COMPUTATION_IGNORE_AGENT_VERSION;
423425
import static datadog.trace.api.config.GeneralConfig.TRACE_TAGS;
@@ -487,6 +489,7 @@
487489
import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_HEADERS;
488490
import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_PROTOCOL;
489491
import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_TIMEOUT;
492+
import static datadog.trace.api.config.OtlpConfig.TRACES_SPAN_METRICS_ENABLED;
490493
import static datadog.trace.api.config.OtlpConfig.TRACE_OTEL_EXPORTER;
491494
import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS;
492495
import static datadog.trace.api.config.ProfilingConfig.PROFILING_AGENTLESS_DEFAULT;
@@ -997,6 +1000,9 @@ public static String getHostName() {
9971000
private final int otlpMetricsTimeout;
9981001
private final OtlpConfig.Temporality otlpMetricsTemporalityPreference;
9991002

1003+
private final boolean tracesSpanMetricsEnabled;
1004+
private final boolean traceOtelSemanticsEnabled;
1005+
10001006
private final String traceOtelExporter;
10011007
private final String otlpTracesEndpoint;
10021008
private final Map<String, String> otlpTracesHeaders;
@@ -1015,6 +1021,7 @@ public static String getHostName() {
10151021
private final boolean tracerMetricsBufferingEnabled;
10161022
private final int tracerMetricsMaxAggregates;
10171023
private final int tracerMetricsMaxPending;
1024+
private final int traceStatsInterval;
10181025

10191026
private final boolean reportHostName;
10201027

@@ -2121,6 +2128,16 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins
21212128
OtlpConfig.Temporality.class,
21222129
OtlpConfig.Temporality.DELTA);
21232130

2131+
traceOtelSemanticsEnabled = configProvider.getBoolean(TRACE_OTEL_SEMANTICS_ENABLED, false);
2132+
// Tri-state default: when unset, SDK-computed OTLP span metrics are emitted iff OTLP trace
2133+
// export and OTLP metrics export are both enabled.
2134+
tracesSpanMetricsEnabled =
2135+
configProvider.getBoolean(
2136+
TRACES_SPAN_METRICS_ENABLED,
2137+
isTraceOtlpExporterEnabled()
2138+
&& isMetricsOtelEnabled()
2139+
&& isMetricsOtlpExporterEnabled());
2140+
21242141
otlpTimeout = configProvider.getInteger(OTLP_TRACES_TIMEOUT, DEFAULT_OTLP_TRACES_TIMEOUT);
21252142
if (otlpTimeout < 0) {
21262143
log.warn("Invalid OTLP traces timeout: {}. The value must be positive", otlpTimeout);
@@ -2200,6 +2217,18 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins
22002217
configProvider.getBoolean(TRACE_STATS_COMPUTATION_IGNORE_AGENT_VERSION, false);
22012218
tracerMetricsBufferingEnabled =
22022219
configProvider.getBoolean(TRACER_METRICS_BUFFERING_ENABLED, false);
2220+
// Internal, test-only override of the stats flush interval. Read directly from the
2221+
// underscore-prefixed env var so it bypasses config-inversion validation and telemetry.
2222+
int statsInterval = DEFAULT_TRACE_STATS_INTERVAL;
2223+
String statsIntervalOverride = ConfigHelper.env("_DD_TRACE_STATS_INTERVAL");
2224+
if (statsIntervalOverride != null) {
2225+
try {
2226+
statsInterval = Integer.parseInt(statsIntervalOverride);
2227+
} catch (NumberFormatException ignored) {
2228+
// fall back to the default
2229+
}
2230+
}
2231+
traceStatsInterval = statsInterval;
22032232
// The metrics inbox is an MpscArrayQueue<SpanSnapshot>; each saturated slot holds one
22042233
// ~120 B SpanSnapshot. The historical default TRACER_METRICS_MAX_PENDING=2048 (logical) *
22052234
// LEGACY_BATCH_SIZE=64 = 131072 slots was sized for the prior conflating-Batch model where
@@ -3831,6 +3860,10 @@ public int getTracerMetricsMaxPending() {
38313860
return tracerMetricsMaxPending;
38323861
}
38333862

3863+
public int getTraceStatsInterval() {
3864+
return traceStatsInterval;
3865+
}
3866+
38343867
public boolean isLogsInjectionEnabled() {
38353868
return logsInjectionEnabled;
38363869
}
@@ -5575,6 +5608,14 @@ public OtlpConfig.Temporality getOtlpMetricsTemporalityPreference() {
55755608
return otlpMetricsTemporalityPreference;
55765609
}
55775610

5611+
public boolean isTracesSpanMetricsEnabled() {
5612+
return tracesSpanMetricsEnabled;
5613+
}
5614+
5615+
public boolean isTraceOtelSemanticsEnabled() {
5616+
return traceOtelSemanticsEnabled;
5617+
}
5618+
55785619
public boolean isTraceOtelEnabled() {
55795620
return instrumenterConfig.isTraceOtelEnabled();
55805621
}
@@ -6681,6 +6722,12 @@ public String toString() {
66816722
+ otlpMetricsTimeout
66826723
+ ", otlpMetricsTemporalityPreference="
66836724
+ otlpMetricsTemporalityPreference
6725+
+ ", tracesSpanMetricsEnabled="
6726+
+ tracesSpanMetricsEnabled
6727+
+ ", traceOtelSemanticsEnabled="
6728+
+ traceOtelSemanticsEnabled
6729+
+ ", traceStatsInterval="
6730+
+ traceStatsInterval
66846731
+ ", traceOtelExporter="
66856732
+ traceOtelExporter
66866733
+ ", otlpTracesEndpoint="

internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import static datadog.trace.api.config.GeneralConfig.SSI_INJECTION_ENABLED
5353
import static datadog.trace.api.config.GeneralConfig.SSI_INJECTION_FORCE
5454
import static datadog.trace.api.config.GeneralConfig.TAGS
5555
import static datadog.trace.api.config.GeneralConfig.TRACER_METRICS_IGNORED_RESOURCES
56+
import static datadog.trace.api.config.GeneralConfig.TRACE_OTEL_SEMANTICS_ENABLED
5657
import static datadog.trace.api.config.GeneralConfig.VERSION
5758
import static datadog.trace.api.config.JmxFetchConfig.JMX_FETCH_CHECK_PERIOD
5859
import static datadog.trace.api.config.JmxFetchConfig.JMX_FETCH_ENABLED
@@ -137,6 +138,7 @@ import static datadog.trace.api.config.OtlpConfig.Protocol.HTTP_JSON
137138
import static datadog.trace.api.config.OtlpConfig.Temporality.CUMULATIVE
138139
import static datadog.trace.api.config.OtlpConfig.Temporality.DELTA
139140
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_ENABLED
141+
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_EXPORTER
140142
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_INTERVAL
141143
import static datadog.trace.api.config.OtlpConfig.METRICS_OTEL_TIMEOUT
142144
import static datadog.trace.api.config.OtlpConfig.OTLP_METRICS_ENDPOINT
@@ -148,7 +150,9 @@ import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_ENDPOINT
148150
import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_HEADERS
149151
import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_PROTOCOL
150152
import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_TIMEOUT
153+
import static datadog.trace.api.config.OtlpConfig.TRACES_SPAN_METRICS_ENABLED
151154
import static datadog.trace.api.config.OtlpConfig.TRACE_OTEL_ENABLED
155+
import static datadog.trace.api.config.OtlpConfig.TRACE_OTEL_EXPORTER
152156
import datadog.trace.config.inversion.ConfigHelper
153157

154158
import datadog.trace.api.env.FixedCapturedEnvironment
@@ -555,6 +559,10 @@ class ConfigTest extends DDSpecification {
555559
config.otlpTracesHeaders == [:]
556560
config.otlpTracesProtocol == HTTP_PROTOBUF
557561
config.otlpTracesTimeout == 10000
562+
563+
!config.tracesSpanMetricsEnabled
564+
!config.traceOtelSemanticsEnabled
565+
config.traceStatsInterval == 10000
558566
}
559567

560568
def "otel: check syntax for OTLP headers"() {
@@ -715,6 +723,36 @@ class ConfigTest extends DDSpecification {
715723
config.otlpTracesEndpoint == "http://localhost:4318/v1/traces"
716724
}
717725

726+
def "traces span metrics tri-state default: exporter=#exporter metricsEnabled=#metricsEnabled metricsExporter=#metricsExporter override=#override"() {
727+
setup:
728+
System.setProperty(PREFIX + TRACE_OTEL_EXPORTER, exporter)
729+
System.setProperty(PREFIX + METRICS_OTEL_ENABLED, metricsEnabled)
730+
if (metricsExporter != null) {
731+
System.setProperty(PREFIX + METRICS_OTEL_EXPORTER, metricsExporter)
732+
}
733+
if (override != null) {
734+
System.setProperty(PREFIX + TRACES_SPAN_METRICS_ENABLED, override)
735+
}
736+
737+
when:
738+
Config config = new Config()
739+
740+
then:
741+
// Unset: emit iff OTLP trace export and OTLP metrics export are both on. An explicit
742+
// dd.traces.span.metrics.enabled always wins.
743+
config.tracesSpanMetricsEnabled == expected
744+
745+
where:
746+
exporter | metricsEnabled | metricsExporter | override | expected
747+
"otlp" | "true" | null | null | true // metrics defaults to otlp
748+
"otlp" | "true" | "otlp" | null | true
749+
"otlp" | "true" | "none" | null | false // metrics exporter explicitly disabled
750+
"otlp" | "false" | "otlp" | null | false // metrics feature flag off overrides exporter
751+
"none" | "true" | null | null | false
752+
"none" | "true" | "otlp" | null | false
753+
"none" | "false" | "none" | "true" | true // explicit override wins
754+
"otlp" | "true" | "otlp" | "false" | false // explicit override wins
755+
}
718756

719757
def "specify overrides via system properties"() {
720758
setup:
@@ -831,6 +869,7 @@ class ConfigTest extends DDSpecification {
831869
System.setProperty(OTEL_EXPORTER_OTLP_TRACES_PROTOCOL_PROP, "http/protobuf")
832870
System.setProperty(OTEL_EXPORTER_OTLP_TRACES_TIMEOUT_PROP, "5002")
833871
System.setProperty(OTEL_RESOURCE_ATTRIBUTES_PROP, "service.name=my=app,service.version=1.0.0,deployment.environment=production")
872+
System.setProperty(PREFIX + TRACE_OTEL_SEMANTICS_ENABLED, "true")
834873

835874
when:
836875
Config config = new Config()
@@ -953,6 +992,9 @@ class ConfigTest extends DDSpecification {
953992
config.otlpTracesHeaders["traces-config-value"] == "T"
954993
config.otlpTracesProtocol == HTTP_PROTOBUF
955994
config.otlpTracesTimeout == 5002
995+
996+
config.traceOtelSemanticsEnabled
997+
config.tracesSpanMetricsEnabled // tri-state default: OTLP trace export + OTel metrics both on
956998
}
957999

9581000
def "specify overrides via env vars"() {

internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSourceTest.groovy

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import static datadog.trace.api.config.GeneralConfig.RUNTIME_METRICS_ENABLED
99
import static datadog.trace.api.config.GeneralConfig.SERVICE_NAME
1010
import static datadog.trace.api.config.GeneralConfig.TAGS
1111
import static datadog.trace.api.config.GeneralConfig.VERSION
12+
import static datadog.trace.api.config.OtlpConfig.TRACES_SPAN_METRICS_ENABLED
1213
import static datadog.trace.api.config.OtlpConfig.TRACE_OTEL_ENABLED
1314
import static datadog.trace.api.config.OtlpConfig.TRACE_OTEL_EXPORTER
1415
import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_ENABLED
@@ -258,6 +259,48 @@ class OtelEnvironmentConfigSourceTest extends DDSpecification {
258259
source.get(TRACE_OTEL_EXPORTER) == 'otlp'
259260
}
260261

262+
def "otel traces span metrics enabled system property is mapped when otel is enabled"() {
263+
setup:
264+
injectSysConfig('dd.trace.otel.enabled', 'true', false)
265+
injectSysConfig('otel.traces.span.metrics.enabled', value, false)
266+
267+
when:
268+
def source = new OtelEnvironmentConfigSource()
269+
270+
then:
271+
source.get(TRACES_SPAN_METRICS_ENABLED) == value
272+
273+
where:
274+
value << ['true', 'false']
275+
}
276+
277+
def "otel traces span metrics enabled environment variable is mapped when otel is enabled"() {
278+
setup:
279+
injectEnvConfig('DD_TRACE_OTEL_ENABLED', 'true', false)
280+
injectEnvConfig('OTEL_TRACES_SPAN_METRICS_ENABLED', value, false)
281+
282+
when:
283+
def source = new OtelEnvironmentConfigSource()
284+
285+
then:
286+
source.get(TRACES_SPAN_METRICS_ENABLED) == value
287+
288+
where:
289+
value << ['true', 'false']
290+
}
291+
292+
def "otel traces span metrics enabled is not mapped when otel is disabled"() {
293+
setup:
294+
// Without dd.trace.otel.enabled, setupTraceOtelEnvironment() does not run.
295+
injectSysConfig('otel.traces.span.metrics.enabled', 'true', false)
296+
297+
when:
298+
def source = new OtelEnvironmentConfigSource()
299+
300+
then:
301+
source.get(TRACES_SPAN_METRICS_ENABLED) == null
302+
}
303+
261304
def "otel traces exporter none still disables tracing"() {
262305
setup:
263306
injectEnvConfig('DD_TRACE_OTEL_ENABLED', 'true', false)

metadata/supported-configurations.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8609,6 +8609,22 @@
86098609
"aliases": []
86108610
}
86118611
],
8612+
"DD_TRACE_OTEL_SEMANTICS_ENABLED": [
8613+
{
8614+
"version": "A",
8615+
"type": "boolean",
8616+
"default": "false",
8617+
"aliases": []
8618+
}
8619+
],
8620+
"DD_TRACES_SPAN_METRICS_ENABLED": [
8621+
{
8622+
"version": "A",
8623+
"type": "boolean",
8624+
"default": null,
8625+
"aliases": []
8626+
}
8627+
],
86128628
"DD_TRACE_ORG_GUARD_ENABLED": [
86138629
{
86148630
"version": "A",
@@ -11601,6 +11617,14 @@
1160111617
"aliases": []
1160211618
}
1160311619
],
11620+
"OTEL_TRACES_SPAN_METRICS_ENABLED": [
11621+
{
11622+
"version": "A",
11623+
"type": "boolean",
11624+
"default": null,
11625+
"aliases": []
11626+
}
11627+
],
1160411628
"OTEL_TRACES_SAMPLER_ARG": [
1160511629
{
1160611630
"version": "C",

utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/OtelEnvironmentConfigSource.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_HEADERS;
3838
import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_PROTOCOL;
3939
import static datadog.trace.api.config.OtlpConfig.OTLP_TRACES_TIMEOUT;
40+
import static datadog.trace.api.config.OtlpConfig.TRACES_SPAN_METRICS_ENABLED;
4041
import static datadog.trace.api.config.OtlpConfig.TRACE_OTEL_ENABLED;
4142
import static datadog.trace.api.config.OtlpConfig.TRACE_OTEL_EXPORTER;
4243
import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_ENABLED;
@@ -161,6 +162,9 @@ private void setupTraceOtelEnvironment() {
161162
capture(REQUEST_HEADER_TAGS, mapHeaderTags("http.request.header.", requestHeaders));
162163
capture(RESPONSE_HEADER_TAGS, mapHeaderTags("http.response.header.", responseHeaders));
163164
capture(TRACE_EXTENSIONS_PATH, extensions);
165+
capture(
166+
TRACES_SPAN_METRICS_ENABLED,
167+
getOtelProperty("otel.traces.span.metrics.enabled", "dd." + TRACES_SPAN_METRICS_ENABLED));
164168

165169
String exporter = getOtelProperty("otel.traces.exporter");
166170
if ("otlp".equalsIgnoreCase(exporter)) { // traces defaults to non-OTLP (i.e. datadog)

0 commit comments

Comments
 (0)