Skip to content

Commit a92b3a6

Browse files
ValentinZakharovdevflow.devflow-routing-intake
andauthored
Tag @async @scheduled spring-scheduling spans as errored on exception (#12071)
Tag @async @scheduled spring-scheduling spans as errored on exception Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
1 parent 1f390b7 commit a92b3a6

8 files changed

Lines changed: 100 additions & 1 deletion

File tree

dd-java-agent/instrumentation/spring/spring-scheduling-3.1/src/main/java/datadog/trace/instrumentation/springscheduling/SpannedMethodInvocation.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,15 @@ private Object invokeWithContinuation(CharSequence spanName) throws Throwable {
5050

5151
private Object invokeWithSpan(CharSequence spanName) throws Throwable {
5252
AgentSpan span = startSpan("spring-scheduling", spanName);
53+
DECORATE.afterStart(span);
54+
DECORATE.measureIfEnabled(span);
5355
try (ContextScope scope = activateSpan(span)) {
54-
return delegate.proceed();
56+
try {
57+
return delegate.proceed();
58+
} catch (Throwable throwable) {
59+
DECORATE.onError(span, throwable);
60+
throw throwable;
61+
}
5562
} finally {
5663
span.finish();
5764
}

dd-java-agent/instrumentation/spring/spring-scheduling-3.1/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingDecorator.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package datadog.trace.instrumentation.springscheduling;
22

3+
import datadog.trace.api.Config;
34
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
45
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
56
import datadog.trace.bootstrap.instrumentation.decorator.BaseDecorator;
@@ -9,6 +10,8 @@ public class SpringSchedulingDecorator extends BaseDecorator {
910
public static final CharSequence SCHEDULED_CALL = UTF8BytesString.create("scheduled.call");
1011
public static final SpringSchedulingDecorator DECORATE = new SpringSchedulingDecorator();
1112

13+
private static final boolean MEASURED = Config.get().isSpringSchedulingMeasuredEnabled();
14+
1215
private SpringSchedulingDecorator() {}
1316

1417
@Override
@@ -26,6 +29,12 @@ protected CharSequence component() {
2629
return "spring-scheduling";
2730
}
2831

32+
public void measureIfEnabled(final AgentSpan span) {
33+
if (MEASURED) {
34+
span.setMeasured(true);
35+
}
36+
}
37+
2938
public void onRun(final AgentSpan span, final Runnable runnable) {
3039
if (runnable != null) {
3140
CharSequence resourceName = "";

dd-java-agent/instrumentation/spring/spring-scheduling-3.1/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingRunnableWrapper.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public void run() {
5959
? startSpan("spring-scheduling", SCHEDULED_CALL)
6060
: startSpan("spring-scheduling", SCHEDULED_CALL, null);
6161
DECORATE.afterStart(span);
62+
DECORATE.measureIfEnabled(span);
6263

6364
try (final ContextScope scope = activateSpan(span)) {
6465
DECORATE.onRun(span, runnable);

dd-java-agent/instrumentation/spring/spring-scheduling-3.1/src/test/groovy/SpringAsyncTest.groovy

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,57 @@
11
import datadog.trace.agent.test.InstrumentationSpecification
2+
import datadog.trace.bootstrap.instrumentation.api.Tags
23
import org.springframework.context.annotation.AnnotationConfigApplicationContext
34

45
import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace
56

67
class SpringAsyncTest extends InstrumentationSpecification {
78

9+
boolean asyncMeasured() {
10+
false
11+
}
12+
13+
@Override
14+
protected void configurePreAgent() {
15+
super.configurePreAgent()
16+
if (asyncMeasured()) {
17+
injectSysConfig("spring-scheduling.measured.enabled", "true")
18+
}
19+
}
20+
21+
def "exception in @async method tags span as errored"() {
22+
setup:
23+
def context = new AnnotationConfigApplicationContext(AsyncTaskConfig)
24+
AsyncTask asyncTask = context.getBean(AsyncTask)
25+
26+
when:
27+
Throwable thrown = null
28+
try {
29+
asyncTask.asyncThrow().join()
30+
} catch (Throwable t) {
31+
thrown = t
32+
}
33+
34+
then:
35+
thrown != null
36+
assertTraces(1) {
37+
trace(1) {
38+
span {
39+
resourceName "AsyncTask.asyncThrow"
40+
errored true
41+
measured asyncMeasured()
42+
tags {
43+
"$Tags.COMPONENT" "spring-scheduling"
44+
errorTags(RuntimeException, "Datadog async repro")
45+
defaultTags()
46+
}
47+
}
48+
}
49+
}
50+
51+
cleanup:
52+
context.close()
53+
}
54+
855
def "context propagated through @async annotation"() {
956
setup:
1057
def context = new AnnotationConfigApplicationContext(AsyncTaskConfig)
@@ -54,3 +101,10 @@ class SpringAsyncTest extends InstrumentationSpecification {
54101
hasParent << [true, false]
55102
}
56103
}
104+
105+
class SpringAsyncMeasuredForkedTest extends SpringAsyncTest {
106+
@Override
107+
boolean asyncMeasured() {
108+
true
109+
}
110+
}

dd-java-agent/instrumentation/spring/spring-scheduling-3.1/src/test/java/AsyncTask.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ public CompletableFuture<Integer> async() {
1010
return CompletableFuture.completedFuture(getInt());
1111
}
1212

13+
@Async
14+
public CompletableFuture<Void> asyncThrow() {
15+
throw new RuntimeException("Datadog async repro");
16+
}
17+
1318
@Trace
1419
public int getInt() {
1520
return ThreadLocalRandom.current().nextInt();

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ public final class TraceInstrumentationConfig {
157157
public static final String SPRING_DATA_REPOSITORY_INTERFACE_RESOURCE_NAME =
158158
"spring-data.repository.interface.resource-name";
159159

160+
public static final String SPRING_SCHEDULING_MEASURED_ENABLED =
161+
"spring-scheduling.measured.enabled";
162+
160163
public static final String INSTRUMENTATION_CONFIG_ID = "instrumentation_config_id";
161164

162165
public static final String RESOLVER_CACHE_CONFIG = "resolver.cache.config";

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@
626626
import static datadog.trace.api.config.TraceInstrumentationConfig.SPARK_APP_NAME_AS_SERVICE;
627627
import static datadog.trace.api.config.TraceInstrumentationConfig.SPARK_TASK_HISTOGRAM_ENABLED;
628628
import static datadog.trace.api.config.TraceInstrumentationConfig.SPRING_DATA_REPOSITORY_INTERFACE_RESOURCE_NAME;
629+
import static datadog.trace.api.config.TraceInstrumentationConfig.SPRING_SCHEDULING_MEASURED_ENABLED;
629630
import static datadog.trace.api.config.TraceInstrumentationConfig.SQS_BODY_PROPAGATION_ENABLED;
630631
import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_128_BIT_TRACEID_LOGGING_ENABLED;
631632
import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_HTTP_CLIENT_TAG_QUERY_STRING;
@@ -1293,6 +1294,8 @@ public static String getHostName() {
12931294
private final boolean hystrixTagsEnabled;
12941295
private final boolean hystrixMeasuredEnabled;
12951296

1297+
private final boolean springSchedulingMeasuredEnabled;
1298+
12961299
private final boolean resilience4jMeasuredEnabled;
12971300
private final boolean resilience4jTagMetricsEnabled;
12981301

@@ -3052,6 +3055,9 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment())
30523055
hystrixTagsEnabled = configProvider.getBoolean(HYSTRIX_TAGS_ENABLED, false);
30533056
hystrixMeasuredEnabled = configProvider.getBoolean(HYSTRIX_MEASURED_ENABLED, false);
30543057

3058+
springSchedulingMeasuredEnabled =
3059+
configProvider.getBoolean(SPRING_SCHEDULING_MEASURED_ENABLED, false);
3060+
30553061
resilience4jMeasuredEnabled = configProvider.getBoolean(RESILIENCE4J_MEASURED_ENABLED, false);
30563062
resilience4jTagMetricsEnabled =
30573063
configProvider.getBoolean(RESILIENCE4J_TAG_METRICS_ENABLED, false);
@@ -4973,6 +4979,10 @@ public boolean isResilience4jMeasuredEnabled() {
49734979
return resilience4jMeasuredEnabled;
49744980
}
49754981

4982+
public boolean isSpringSchedulingMeasuredEnabled() {
4983+
return springSchedulingMeasuredEnabled;
4984+
}
4985+
49764986
public boolean isResilience4jTagMetricsEnabled() {
49774987
return resilience4jTagMetricsEnabled;
49784988
}
@@ -6666,6 +6676,8 @@ public String toString() {
66666676
+ hystrixTagsEnabled
66676677
+ ", hystrixMeasuredEnabled="
66686678
+ hystrixMeasuredEnabled
6679+
+ ", springSchedulingMeasuredEnabled="
6680+
+ springSchedulingMeasuredEnabled
66696681
+ ", resilience4jMeasuredEnable="
66706682
+ resilience4jMeasuredEnabled
66716683
+ ", resilience4jTagMetricsEnabled="

metadata/supported-configurations.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3897,6 +3897,14 @@
38973897
"aliases": []
38983898
}
38993899
],
3900+
"DD_SPRING_SCHEDULING_MEASURED_ENABLED": [
3901+
{
3902+
"version": "A",
3903+
"type": "boolean",
3904+
"default": "false",
3905+
"aliases": []
3906+
}
3907+
],
39003908
"DD_STACK_TRACE_LENGTH_LIMIT": [
39013909
{
39023910
"version": "A",

0 commit comments

Comments
 (0)