1
1
package datadog .trace .instrumentation .scalatest ;
2
2
3
+ import static datadog .trace .agent .tooling .bytebuddy .matcher .HierarchyMatchers .implementsInterface ;
3
4
import static datadog .trace .agent .tooling .bytebuddy .matcher .NameMatchers .named ;
4
5
import static net .bytebuddy .matcher .ElementMatchers .takesArgument ;
5
6
import static net .bytebuddy .matcher .ElementMatchers .takesArguments ;
6
7
7
8
import com .google .auto .service .AutoService ;
8
9
import datadog .trace .agent .tooling .Instrumenter ;
9
10
import datadog .trace .agent .tooling .InstrumenterModule ;
11
+ import datadog .trace .bootstrap .CallDepthThreadLocalMap ;
10
12
import java .util .Set ;
11
13
import net .bytebuddy .asm .Advice ;
14
+ import net .bytebuddy .description .type .TypeDescription ;
15
+ import net .bytebuddy .matcher .ElementMatcher ;
16
+ import org .scalatest .Reporter ;
12
17
import org .scalatest .events .Event ;
13
18
14
19
@ AutoService (InstrumenterModule .class )
15
20
public class ScalatestInstrumentation extends InstrumenterModule .CiVisibility
16
- implements Instrumenter .ForSingleType , Instrumenter .HasMethodAdvice {
21
+ implements Instrumenter .ForTypeHierarchy , Instrumenter .HasMethodAdvice {
17
22
18
23
public ScalatestInstrumentation () {
19
24
super ("ci-visibility" , "scalatest" );
@@ -25,8 +30,13 @@ public boolean isApplicable(Set<TargetSystem> enabledSystems) {
25
30
}
26
31
27
32
@ Override
28
- public String instrumentedType () {
29
- return "org.scalatest.DispatchReporter" ;
33
+ public String hierarchyMarkerType () {
34
+ return "org.scalatest.Reporter" ;
35
+ }
36
+
37
+ @ Override
38
+ public ElementMatcher <TypeDescription > hierarchyMatcher () {
39
+ return implementsInterface (named (hierarchyMarkerType ()));
30
40
}
31
41
32
42
@ Override
@@ -51,8 +61,13 @@ public void methodAdvice(MethodTransformer transformer) {
51
61
public static class DispatchEventAdvice {
52
62
@ Advice .OnMethodEnter
53
63
public static void onDispatchEvent (@ Advice .Argument (value = 0 ) Event event ) {
64
+ if (CallDepthThreadLocalMap .incrementCallDepth (Reporter .class ) != 0 ) {
65
+ // nested call
66
+ return ;
67
+ }
68
+
54
69
// Instead of registering our reporter using Scalatest's standard "-C" argument,
55
- // we hook into internal dispatch reporter.
70
+ // we hook into internal reporter.
56
71
// The reason is that Scalatest invokes registered reporters in a separate thread,
57
72
// while we need to process events in the thread where they originate.
58
73
// This is required because test span has to be active in the thread where
@@ -61,5 +76,10 @@ public static void onDispatchEvent(@Advice.Argument(value = 0) Event event) {
61
76
// could be properly associated with it.
62
77
DatadogReporter .handle (event );
63
78
}
79
+
80
+ @ Advice .OnMethodExit
81
+ public static void afterDispatchEvent () {
82
+ CallDepthThreadLocalMap .decrementCallDepth (Reporter .class );
83
+ }
64
84
}
65
85
}
0 commit comments