Skip to content

Commit b8c4494

Browse files
committed
initial checkin
1 parent abf68b9 commit b8c4494

File tree

12 files changed

+372
-0
lines changed

12 files changed

+372
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
.java-version
22
.git
33
.github
4+
.settings
5+
.classpath
6+
.project
7+
bin
8+
build

settings.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
rootProject.name = 'java-instrumentation-template'
2+
include 'spring-async'
3+
include 'spring-web-async'

spring-async/build.gradle

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
// Build.gradle generated for instrumentation module spring-web-async
3+
4+
apply plugin: 'java'
5+
6+
dependencies {
7+
implementation 'org.springframework:spring-core:5.0.0.RELEASE'
8+
9+
// New Relic Java Agent dependencies
10+
implementation 'com.newrelic.agent.java:newrelic-agent:6.4.0'
11+
implementation 'com.newrelic.agent.java:newrelic-api:6.4.0'
12+
implementation fileTree(include: ['*.jar'], dir: '../libs')
13+
implementation fileTree(include: ['*.jar'], dir: '../test-lib')
14+
}
15+
16+
jar {
17+
manifest {
18+
attributes 'Implementation-Title': 'com.newrelic.instrumentation.spring-async'
19+
attributes 'Implementation-Vendor': 'New Relic'
20+
attributes 'Implementation-Vendor-Id': 'com.newrelic'
21+
attributes 'Implementation-Version': 1.0
22+
}
23+
}
24+
25+
verifyInstrumentation {
26+
passes 'org.springframework:spring-core:[5.0.0.RELEASE,)'
27+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.newrelic.instrumentation.spring.web.async;
2+
3+
import java.util.concurrent.Callable;
4+
5+
import com.newrelic.agent.bridge.AgentBridge;
6+
import com.newrelic.api.agent.NewRelic;
7+
import com.newrelic.api.agent.Token;
8+
import com.newrelic.api.agent.Trace;
9+
10+
public class NRCallableWrapper<V> implements Callable<V> {
11+
12+
private Callable<V> delegate = null;
13+
private Token token = null;
14+
private static boolean isTransformed = false;
15+
16+
public NRCallableWrapper(Callable<V> d, Token t) {
17+
delegate = d;
18+
token = t;
19+
if(!isTransformed) {
20+
AgentBridge.instrumentation.retransformUninstrumentedClass(getClass());
21+
isTransformed = true;
22+
}
23+
}
24+
25+
@Override
26+
@Trace(async = true)
27+
public V call() throws Exception {
28+
if(token != null) {
29+
NewRelic.getAgent().getTracedMethod().setMetricName("Custom","SpringAsync","Callable");
30+
token.linkAndExpire();
31+
token = null;
32+
}
33+
return delegate.call();
34+
}
35+
36+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.newrelic.instrumentation.spring.web.async;
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+
public class NRRunnableWrapper implements Runnable {
9+
10+
private static boolean isTransformed = false;
11+
private Runnable delegate = null;
12+
private Token token = null;
13+
14+
public NRRunnableWrapper(Runnable r, Token t) {
15+
delegate = r;
16+
token = t;
17+
if(!isTransformed) {
18+
isTransformed = true;
19+
AgentBridge.instrumentation.retransformUninstrumentedClass(getClass());
20+
}
21+
}
22+
23+
@Override
24+
@Trace(async = true)
25+
public void run() {
26+
if(token != null) {
27+
NewRelic.getAgent().getTracedMethod().setMetricName("Custom","SpringAsync","Runnable");
28+
token.linkAndExpire();
29+
token = null;
30+
}
31+
delegate.run();
32+
}
33+
34+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.newrelic.instrumentation.spring.web.async;
2+
3+
import java.util.concurrent.Callable;
4+
5+
import com.newrelic.api.agent.NewRelic;
6+
import com.newrelic.api.agent.Token;
7+
8+
public class Utils {
9+
10+
public static Runnable getWrappedRunnable(Runnable r) {
11+
12+
if(r instanceof NRRunnableWrapper) return null;
13+
14+
String packageName = r.getClass().getPackage().getName();
15+
if(packageName.startsWith("com.newrelic")) return null;
16+
17+
Token token = NewRelic.getAgent().getTransaction().getToken();
18+
if(token != null && token.isActive()) {
19+
return new NRRunnableWrapper(r, token);
20+
} else if(token != null) {
21+
token.expire();
22+
token = null;
23+
}
24+
return null;
25+
}
26+
27+
public static <V> Callable<V> getWrappedCallable(Callable<V> c) {
28+
29+
if(c instanceof NRCallableWrapper) return null;
30+
31+
String packageName = c.getClass().getPackage().getName();
32+
if(packageName.startsWith("com.newrelic")) return null;
33+
34+
Token token = NewRelic.getAgent().getTransaction().getToken();
35+
if(token != null && token.isActive()) {
36+
return new NRCallableWrapper<V>(c, token);
37+
} else if(token != null) {
38+
token.expire();
39+
token = null;
40+
}
41+
return null;
42+
}
43+
44+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.springframework.core.task;
2+
3+
import com.newrelic.api.agent.weaver.Weave;
4+
import com.newrelic.api.agent.weaver.Weaver;
5+
import com.newrelic.instrumentation.spring.web.async.Utils;
6+
7+
@Weave
8+
public abstract class SimpleAsyncTaskExecutor {
9+
10+
11+
protected void doExecute(Runnable task) {
12+
Runnable wrapper = Utils.getWrappedRunnable(task);
13+
if(wrapper != null) {
14+
task = wrapper;
15+
}
16+
Weaver.callOriginal();
17+
}
18+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.springframework.core.task.support;
2+
3+
import java.util.concurrent.Callable;
4+
import java.util.concurrent.Future;
5+
6+
import org.springframework.util.concurrent.ListenableFuture;
7+
8+
import com.newrelic.api.agent.weaver.Weave;
9+
import com.newrelic.api.agent.weaver.Weaver;
10+
import com.newrelic.instrumentation.spring.web.async.Utils;
11+
12+
@Weave
13+
public abstract class TaskExecutorAdapter {
14+
15+
public void execute(Runnable task) {
16+
Runnable wrapper = Utils.getWrappedRunnable(task);
17+
if(wrapper != null) {
18+
task = wrapper;
19+
}
20+
Weaver.callOriginal();
21+
}
22+
23+
public Future<?> submit(Runnable task) {
24+
Runnable wrapper = Utils.getWrappedRunnable(task);
25+
if(wrapper != null) {
26+
task = wrapper;
27+
}
28+
return Weaver.callOriginal();
29+
}
30+
31+
public <T> Future<T> submit(Callable<T> task) {
32+
Callable<T> wrapper = Utils.getWrappedCallable(task);
33+
if(wrapper != null) {
34+
task = wrapper;
35+
}
36+
return Weaver.callOriginal();
37+
}
38+
39+
public ListenableFuture<?> submitListenable(Runnable task) {
40+
Runnable wrapper = Utils.getWrappedRunnable(task);
41+
if(wrapper != null) {
42+
task = wrapper;
43+
}
44+
return Weaver.callOriginal();
45+
}
46+
47+
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
48+
Callable<T> wrapper = Utils.getWrappedCallable(task);
49+
if(wrapper != null) {
50+
task = wrapper;
51+
}
52+
return Weaver.callOriginal();
53+
}
54+
}

spring-web-async/build.gradle

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
// Build.gradle generated for instrumentation module spring-web-async
3+
4+
apply plugin: 'java'
5+
6+
dependencies {
7+
implementation 'org.springframework:spring-web:5.0.0.RELEASE'
8+
9+
// New Relic Java Agent dependencies
10+
implementation 'com.newrelic.agent.java:newrelic-agent:6.4.0'
11+
implementation 'com.newrelic.agent.java:newrelic-api:6.4.0'
12+
implementation fileTree(include: ['*.jar'], dir: '../libs')
13+
implementation fileTree(include: ['*.jar'], dir: '../test-lib')
14+
}
15+
16+
jar {
17+
manifest {
18+
attributes 'Implementation-Title': 'com.newrelic.instrumentation.spring-web-async'
19+
attributes 'Implementation-Vendor': 'New Relic'
20+
attributes 'Implementation-Vendor-Id': 'com.newrelic'
21+
attributes 'Implementation-Version': 1.0
22+
}
23+
}
24+
25+
verifyInstrumentation {
26+
passes 'org.springframework:spring-web:[5.0.0.RELEASE,)'
27+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.newrelic.instrumentation.spring.web.async;
2+
3+
import java.util.concurrent.Callable;
4+
5+
import com.newrelic.agent.bridge.AgentBridge;
6+
import com.newrelic.api.agent.Token;
7+
import com.newrelic.api.agent.Trace;
8+
9+
public class NRCallableWrapper<V> implements Callable<V> {
10+
11+
private static boolean isTransformed = false;
12+
private Callable<V> delegate = null;
13+
private Token token = null;
14+
15+
public NRCallableWrapper(Callable<V> d, Token t) {
16+
if(!isTransformed) {
17+
AgentBridge.instrumentation.retransformUninstrumentedClass(getClass());
18+
isTransformed = true;
19+
}
20+
delegate = d;
21+
token = t;
22+
}
23+
24+
@Override
25+
@Trace(async = true)
26+
public V call() throws Exception {
27+
if(token != null) {
28+
token.link();
29+
}
30+
return delegate.call();
31+
}
32+
33+
public void linkToken() {
34+
if(token != null) {
35+
token.link();
36+
}
37+
}
38+
39+
public void expireToken() {
40+
if(token != null) {
41+
token.expire();
42+
token = null;
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)