Skip to content

Commit f86aad6

Browse files
authored
Merge pull request #3 from newrelic-experimental/suspend
Suspend
2 parents 6357e23 + 76a8379 commit f86aad6

40 files changed

+1797
-384
lines changed

Kotlin-Coroutines_1.2/build.gradle

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ jar {
2222
}
2323

2424
verifyInstrumentation {
25-
passes 'org.jetbrains.kotlinx:kotlinx-coroutines-core:[1.2.0,)'
25+
passes 'org.jetbrains.kotlinx:kotlinx-coroutines-core:[1.2.0,1.4.0)'
26+
passes 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:[1.3.9,1.4.0)'
2627
excludeRegex '.*SNAPSHOT'
2728
excludeRegex '.*alpha'
2829
excludeRegex '.*-eap-.*'
2930
excludeRegex '.*-native-.*'
30-
}
31+
excludeRegex '.*-M[0-9]'
32+
excludeRegex '.*-rc'
33+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.newrelic.instrumentation.kotlin.coroutines;
2+
3+
import com.newrelic.agent.bridge.AgentBridge;
4+
import com.newrelic.api.agent.NewRelic;
5+
import com.newrelic.api.agent.Token;
6+
import com.newrelic.api.agent.Trace;
7+
8+
import kotlin.coroutines.Continuation;
9+
import kotlin.coroutines.CoroutineContext;
10+
11+
public class NRContinuationWrapper<T> implements Continuation<T> {
12+
13+
private Continuation<T> delegate = null;
14+
private String name = null;
15+
private static boolean isTransformed = false;
16+
17+
public NRContinuationWrapper(Continuation<T> d, String n) {
18+
delegate = d;
19+
name = n;
20+
if(!isTransformed) {
21+
AgentBridge.instrumentation.retransformUninstrumentedClass(getClass());
22+
isTransformed = true;
23+
}
24+
}
25+
26+
@Override
27+
public CoroutineContext getContext() {
28+
return delegate.getContext();
29+
}
30+
31+
@Override
32+
@Trace(async=true)
33+
public void resumeWith(Object p0) {
34+
35+
NewRelic.getAgent().getTracedMethod().setMetricName("Custom","ContinuationWrapper","resumeWith",name != null ? name : Utils.getCoroutineName(getContext(), delegate));
36+
Token token = Utils.getToken(getContext());
37+
if(token != null) {
38+
token.link();
39+
}
40+
delegate.resumeWith(p0);
41+
}
42+
43+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.newrelic.instrumentation.kotlin.coroutines;
2+
3+
import com.newrelic.api.agent.Token;
4+
5+
import kotlin.coroutines.AbstractCoroutineContextElement;
6+
import kotlin.coroutines.CoroutineContext;
7+
8+
public class NRCoroutineToken extends AbstractCoroutineContextElement
9+
{
10+
public static Key key = new Key();
11+
12+
public NRCoroutineToken(Token t) {
13+
super(key);
14+
token = t;
15+
}
16+
17+
private Token token = null;
18+
19+
public static final class Key implements CoroutineContext.Key<NRCoroutineToken> {
20+
private Key() {}
21+
}
22+
23+
public Token getToken() {
24+
return token;
25+
}
26+
27+
@Override
28+
public int hashCode() {
29+
return token.hashCode();
30+
}
31+
32+
@Override
33+
public boolean equals(Object obj) {
34+
if(this != obj ) {
35+
if(obj instanceof NRCoroutineToken) {
36+
NRCoroutineToken t = (NRCoroutineToken)obj;
37+
return t.token == token;
38+
}
39+
} else {
40+
return true;
41+
}
42+
return false;
43+
}
44+
45+
@Override
46+
public String toString() {
47+
return "NRCoroutineToken";
48+
}
49+
50+
51+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.newrelic.instrumentation.kotlin.coroutines;
2+
3+
import com.newrelic.agent.bridge.AgentBridge;
4+
import com.newrelic.api.agent.NewRelic;
5+
import com.newrelic.api.agent.Trace;
6+
7+
import kotlin.jvm.functions.Function1;
8+
9+
public class NRFunction1Wrapper<P1,R> implements Function1<P1, R> {
10+
11+
private Function1<P1, R> delegate = null;
12+
private String name = null;
13+
private static boolean isTransformed = false;
14+
15+
public NRFunction1Wrapper(Function1<P1, R> d, String n) {
16+
delegate = d;
17+
name = n;
18+
if(!isTransformed) {
19+
isTransformed = true;
20+
AgentBridge.instrumentation.retransformUninstrumentedClass(getClass());
21+
}
22+
}
23+
24+
@Override
25+
@Trace(dispatcher=true)
26+
public R invoke(P1 p1) {
27+
if(name != null) NewRelic.getAgent().getTracedMethod().setMetricName("Custom","WrappedSuspend",name);
28+
if(delegate != null) {
29+
return delegate.invoke(p1);
30+
}
31+
return null;
32+
}
33+
34+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.newrelic.instrumentation.kotlin.coroutines;
2+
3+
import com.newrelic.agent.bridge.AgentBridge;
4+
import com.newrelic.api.agent.NewRelic;
5+
import com.newrelic.api.agent.Token;
6+
import com.newrelic.api.agent.Trace;
7+
8+
import kotlin.coroutines.Continuation;
9+
import kotlin.coroutines.CoroutineContext;
10+
import kotlin.jvm.functions.Function2;
11+
import kotlinx.coroutines.CoroutineScope;
12+
13+
public class NRFunction2Wrapper<P1, P2, R> implements Function2<P1, P2, R> {
14+
15+
private Function2<P1, P2, R> delegate = null;
16+
private String name = null;
17+
private static boolean isTransformed = false;
18+
19+
public NRFunction2Wrapper(Function2<P1, P2, R> d,String n) {
20+
delegate = d;
21+
name = n;
22+
if(!isTransformed) {
23+
isTransformed = true;
24+
AgentBridge.instrumentation.retransformUninstrumentedClass(getClass());
25+
}
26+
}
27+
28+
@SuppressWarnings({ "rawtypes", "unchecked" })
29+
@Override
30+
@Trace(async=true)
31+
public R invoke(P1 p1, P2 p2) {
32+
String nameStr = null;
33+
boolean linked = false;
34+
if(p1 instanceof CoroutineContext) {
35+
CoroutineContext ctx = (CoroutineContext)p1;
36+
nameStr = Utils.getCoroutineName(ctx);
37+
Token token = Utils.getToken(ctx);
38+
if(token != null) {
39+
token.link();
40+
linked = true;
41+
}
42+
}
43+
if(p1 instanceof CoroutineScope) {
44+
CoroutineScope scope = (CoroutineScope)p1;
45+
nameStr = Utils.getCoroutineName(scope.getCoroutineContext());
46+
if (!linked) {
47+
Token token = Utils.getToken(scope.getCoroutineContext());
48+
if (token != null) {
49+
token.link();
50+
linked = true;
51+
}
52+
}
53+
}
54+
if(p2 instanceof Continuation) {
55+
Continuation continuation = (Continuation)p2;
56+
if(nameStr == null) nameStr = Utils.getCoroutineName(continuation.getContext(), continuation);
57+
if(nameStr == null || nameStr.equals(Utils.CREATEMETHOD1) || nameStr.equals(Utils.CREATEMETHOD2)) nameStr = name;
58+
59+
if(!linked) {
60+
Token token = Utils.getToken(continuation.getContext());
61+
if (token != null) {
62+
token.link();
63+
linked = true;
64+
}
65+
}
66+
67+
if (!Utils.ignoreContinuation(name) && !Utils.ignoreContinuation(continuation.getClass(), continuation.getContext())) {
68+
NRContinuationWrapper wrapper = new NRContinuationWrapper(continuation, nameStr);
69+
p2 = (P2) wrapper;
70+
}
71+
}
72+
if(nameStr == null) {
73+
nameStr = name;
74+
}
75+
if(nameStr != null) {
76+
NewRelic.getAgent().getTracedMethod().setMetricName("Custom","WrappedSuspend",nameStr);
77+
}
78+
if(delegate != null) {
79+
return delegate.invoke(p1, p2);
80+
}
81+
return null;
82+
}
83+
84+
}

Kotlin-Coroutines_1.2/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/NRRunnable.java

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)