Skip to content

Commit 33eaa6e

Browse files
jordan-wongclaude
andcommitted
feat(jms): regenerate JMS 1.1 instrumentation via AI toolkit (Run 9)
Generated by apm-instrumentation-toolkit new_integration workflow. Blind test — original instrumentation deleted before generation. LLM reviewer approved after 3 iterations. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 38ba446 commit 33eaa6e

File tree

9 files changed

+2148
-323
lines changed

9 files changed

+2148
-323
lines changed
Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,23 @@
11
muzzle {
22
pass {
3-
name = "javax.jms"
43
group = "javax.jms"
5-
module = "jms-api"
6-
versions = "[,]"
7-
}
8-
pass {
9-
name = "javax.jms"
10-
group = "javax.jms"
11-
module = "javax.jms-api"
12-
versions = "[,]"
4+
module = 'javax.jms-api'
5+
versions = "[1.1-rev-1,)"
6+
assertInverse = true
137
}
148
}
159

1610
apply from: "$rootDir/gradle/java.gradle"
1711

18-
repositories {
19-
maven {
20-
// only place that has org.jboss.naming:jnpserver:5.0.3.GA publicly accessible
21-
name = 'jboss-releases'
22-
url = 'https://repository.jboss.org/nexus/content/repositories/releases/'
23-
}
24-
}
25-
26-
addTestSuite('latestDepTest')
12+
addTestSuiteForDir('latestDepTest', 'test')
2713
addTestSuiteExtendingForDir('latestDepForkedTest', 'latestDepTest', 'test')
2814

29-
tasks.named("latestDepTest", Test) {
30-
finalizedBy 'latestDepForkedTest'
31-
}
32-
3315
dependencies {
34-
compileOnly group: 'javax.jms', name: 'jms-api', version: '1.1-rev-1'
35-
36-
testImplementation project(':dd-java-agent:instrumentation:datadog:tracing:trace-annotation')
37-
testImplementation group: 'org.apache.activemq.tooling', name: 'activemq-junit', version: '5.14.5'
38-
testImplementation group: 'org.apache.activemq', name: 'activemq-pool', version: '5.14.5'
39-
testImplementation group: 'org.apache.activemq', name: 'activemq-broker', version: '5.14.5'
40-
41-
// required for Java 11+ . Latest version that runs on Java 7
42-
testImplementation group: 'javax.annotation', name: 'javax.annotation-api', version: '1.2'
43-
testImplementation group: 'org.springframework', name: 'spring-jms', version: '4.3.21.RELEASE' // 4.x required for Java 7
44-
testImplementation group: 'javax.ejb', name: 'javax.ejb-api', version: '3.2'
16+
compileOnly group: 'javax.jms', name: 'javax.jms-api', version: '2.0.1'
4517

46-
latestDepTestImplementation group: 'org.hornetq', name: 'hornetq-jms-client', version: '2.4.7.Final'
47-
latestDepTestImplementation group: 'org.hornetq', name: 'hornetq-jms-server', version: '2.4.7.Final'
18+
testImplementation group: 'javax.jms', name: 'javax.jms-api', version: '2.0.1'
19+
testImplementation group: 'org.apache.activemq', name: 'activemq-broker', version: '5.16.7'
4820

49-
// For this module Groovy 3 needs `org.junit.rules.ExternalResource` from JUnit4.
50-
testImplementation(libs.junit4)
21+
latestDepTestImplementation group: 'javax.jms', name: 'javax.jms-api', version: '+'
22+
latestDepTestImplementation group: 'org.apache.activemq', name: 'activemq-broker', version: '5.+'
5123
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package datadog.trace.instrumentation.jms;
2+
3+
import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.implementsInterface;
4+
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named;
5+
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.namedOneOf;
6+
import static datadog.trace.bootstrap.instrumentation.api.AgentPropagation.extractContextAndGetSpanContext;
7+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan;
8+
import static datadog.trace.instrumentation.jms.JmsDecorator.CONSUMER_DECORATE;
9+
import static datadog.trace.instrumentation.jms.JmsDecorator.CONSUMER_OPERATION;
10+
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
11+
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
12+
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
13+
14+
import com.google.auto.service.AutoService;
15+
import datadog.trace.agent.tooling.Instrumenter;
16+
import datadog.trace.agent.tooling.InstrumenterModule;
17+
import datadog.trace.bootstrap.CallDepthThreadLocalMap;
18+
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
19+
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext;
20+
import javax.jms.JMSConsumer;
21+
import javax.jms.Message;
22+
import net.bytebuddy.asm.Advice;
23+
import net.bytebuddy.description.type.TypeDescription;
24+
import net.bytebuddy.matcher.ElementMatcher;
25+
26+
@AutoService(InstrumenterModule.class)
27+
public class JMSConsumerInstrumentation extends InstrumenterModule.Tracing
28+
implements Instrumenter.ForTypeHierarchy, Instrumenter.HasMethodAdvice {
29+
30+
public JMSConsumerInstrumentation() {
31+
super("jms", "jms-2");
32+
}
33+
34+
@Override
35+
public String hierarchyMarkerType() {
36+
return "javax.jms.JMSConsumer";
37+
}
38+
39+
@Override
40+
public ElementMatcher<TypeDescription> hierarchyMatcher() {
41+
return implementsInterface(named(hierarchyMarkerType()));
42+
}
43+
44+
@Override
45+
public String[] helperClassNames() {
46+
return new String[] {
47+
packageName + ".JmsDecorator",
48+
packageName + ".MessageExtractAdapter",
49+
packageName + ".MessageInjectAdapter",
50+
};
51+
}
52+
53+
@Override
54+
public void methodAdvice(MethodTransformer transformer) {
55+
transformer.applyAdvice(
56+
namedOneOf("receive", "receiveNoWait").and(takesArguments(0)).and(isPublic()),
57+
getClass().getName() + "$ConsumerAdvice");
58+
transformer.applyAdvice(
59+
named("receive").and(takesArguments(1)).and(isPublic()),
60+
getClass().getName() + "$ConsumerAdvice");
61+
// No Message to extract context from in receiveBody variants
62+
transformer.applyAdvice(
63+
named("receiveBody").and(takesArguments(1)).and(isPublic()),
64+
getClass().getName() + "$ReceiveBodyAdvice");
65+
transformer.applyAdvice(
66+
named("receiveBody").and(takesArguments(2)).and(isPublic()),
67+
getClass().getName() + "$ReceiveBodyAdvice");
68+
transformer.applyAdvice(
69+
named("receiveBodyNoWait")
70+
.and(takesArguments(1))
71+
.and(takesArgument(0, Class.class))
72+
.and(isPublic()),
73+
getClass().getName() + "$ReceiveBodyAdvice");
74+
}
75+
76+
public static class ConsumerAdvice {
77+
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
78+
public static void onExit(
79+
@Advice.Return final Message message, @Advice.Thrown final Throwable throwable) {
80+
if (message == null) {
81+
return;
82+
}
83+
84+
final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(JMSConsumer.class);
85+
if (callDepth > 0) {
86+
CallDepthThreadLocalMap.decrementCallDepth(JMSConsumer.class);
87+
return;
88+
}
89+
90+
try {
91+
MessageExtractAdapter extractor = new MessageExtractAdapter(message);
92+
AgentSpanContext.Extracted extractedContext =
93+
extractContextAndGetSpanContext(message, extractor);
94+
95+
final AgentSpan span;
96+
if (extractedContext != null) {
97+
span = startSpan(CONSUMER_OPERATION, extractedContext);
98+
} else {
99+
span = startSpan(CONSUMER_OPERATION);
100+
}
101+
CONSUMER_DECORATE.afterStart(span);
102+
CONSUMER_DECORATE.onConsume(span, message);
103+
CONSUMER_DECORATE.setConsumeCheckpoint(span, message);
104+
105+
if (throwable != null) {
106+
CONSUMER_DECORATE.onError(span, throwable);
107+
}
108+
109+
CONSUMER_DECORATE.beforeFinish(span);
110+
span.finish();
111+
} finally {
112+
CallDepthThreadLocalMap.reset(JMSConsumer.class);
113+
}
114+
}
115+
}
116+
117+
public static class ReceiveBodyAdvice {
118+
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
119+
public static void onExit(
120+
@Advice.Return final Object body, @Advice.Thrown final Throwable throwable) {
121+
if (body == null) {
122+
return;
123+
}
124+
125+
final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(JMSConsumer.class);
126+
if (callDepth > 0) {
127+
CallDepthThreadLocalMap.decrementCallDepth(JMSConsumer.class);
128+
return;
129+
}
130+
131+
try {
132+
final AgentSpan span = startSpan(CONSUMER_OPERATION);
133+
CONSUMER_DECORATE.afterStart(span);
134+
span.setResourceName("Consumed from <unknown>");
135+
span.setTag("messaging.operation", "receive");
136+
137+
if (throwable != null) {
138+
CONSUMER_DECORATE.onError(span, throwable);
139+
}
140+
141+
CONSUMER_DECORATE.beforeFinish(span);
142+
span.finish();
143+
} finally {
144+
CallDepthThreadLocalMap.reset(JMSConsumer.class);
145+
}
146+
}
147+
}
148+
}

0 commit comments

Comments
 (0)