From 0644b68d0941472557725c87cfd39d915896a988 Mon Sep 17 00:00:00 2001 From: Adrien Boitreaud Date: Thu, 30 Apr 2026 17:09:08 +0200 Subject: [PATCH 1/2] Add spark.openlineage.appName tag to spark.application spans --- .../spark/AbstractDatadogSparkListener.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dd-java-agent/instrumentation/spark/spark-common/src/main/java/datadog/trace/instrumentation/spark/AbstractDatadogSparkListener.java b/dd-java-agent/instrumentation/spark/spark-common/src/main/java/datadog/trace/instrumentation/spark/AbstractDatadogSparkListener.java index 4bcfa591f4d..292719f31fd 100644 --- a/dd-java-agent/instrumentation/spark/spark-common/src/main/java/datadog/trace/instrumentation/spark/AbstractDatadogSparkListener.java +++ b/dd-java-agent/instrumentation/spark/spark-common/src/main/java/datadog/trace/instrumentation/spark/AbstractDatadogSparkListener.java @@ -284,6 +284,7 @@ private void initApplicationSpanIfNotInitialized() { captureApplicationParameters(builder); captureEmrStepId(builder); + captureOpenlineageJobInfo(builder); Optional openlineageParentContext = OpenlineageParentContext.from(sparkConf); @@ -299,6 +300,13 @@ private void initApplicationSpanIfNotInitialized() { applicationSpan.setMeasured(true); } + private void captureOpenlineageJobInfo(AgentTracer.SpanBuilder builder) { + String olAppName = sparkConf.get("spark.openlineage.appName", null); + if (olAppName != null) { + builder.withTag("spark.openlineage.appName", olAppName); + } + } + private void captureOpenlineageContextIfPresent( AgentTracer.SpanBuilder builder, OpenlineageParentContext context) { builder.asChildOf(context); From c4bac7b33586fd71fdf12cb2c11c4d35a363813d Mon Sep 17 00:00:00 2001 From: Adrien Boitreaud Date: Thu, 30 Apr 2026 17:10:47 +0200 Subject: [PATCH 2/2] Test spark.openlineage.appName tag on spark.application spans --- .../spark/AbstractSparkListenerTest.groovy | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/dd-java-agent/instrumentation/spark/spark-common/src/testFixtures/groovy/datadog/trace/instrumentation/spark/AbstractSparkListenerTest.groovy b/dd-java-agent/instrumentation/spark/spark-common/src/testFixtures/groovy/datadog/trace/instrumentation/spark/AbstractSparkListenerTest.groovy index 0ccb4071659..a5ebb71915d 100644 --- a/dd-java-agent/instrumentation/spark/spark-common/src/testFixtures/groovy/datadog/trace/instrumentation/spark/AbstractSparkListenerTest.groovy +++ b/dd-java-agent/instrumentation/spark/spark-common/src/testFixtures/groovy/datadog/trace/instrumentation/spark/AbstractSparkListenerTest.groovy @@ -721,6 +721,48 @@ abstract class AbstractSparkListenerTest extends InstrumentationSpecification { .getOption("spark.openlineage.circuitBreaker.timeoutInSeconds") == Option.apply("120") } + def "sets spark.openlineage.appName tag when configured"() { + setup: + def conf = new SparkConf() + conf.set("spark.openlineage.appName", "my-ol-app-name") + def listener = getTestDatadogSparkListener(conf) + + when: + listener.onApplicationStart(applicationStartEvent(1000L)) + listener.onApplicationEnd(new SparkListenerApplicationEnd(2000L)) + + then: + assertTraces(1) { + trace(1) { + span { + operationName "spark.application" + spanType "spark" + assert span.tags["spark.openlineage.appName"] == "my-ol-app-name" + } + } + } + } + + def "does not set spark.openlineage.appName tag when not configured"() { + setup: + def listener = getTestDatadogSparkListener() + + when: + listener.onApplicationStart(applicationStartEvent(1000L)) + listener.onApplicationEnd(new SparkListenerApplicationEnd(2000L)) + + then: + assertTraces(1) { + trace(1) { + span { + operationName "spark.application" + spanType "spark" + assert !span.tags.containsKey("spark.openlineage.appName") + } + } + } + } + protected validateRelativeError(double value, double expected, double relativeAccuracy) { double relativeError = Math.abs(value - expected) / expected assert relativeError < relativeAccuracy