Fix for Spring JMS listeners
MODIFY
dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/AdditionalLibraryIgnoresMatcher.java
dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/AdditionalLibraryIgnoresMatcher.java
@@ -50,7 +50,6 @@ public class AdditionalLibraryIgnoresMatcher<T extends TypeDescription>
|| name.startsWith("org.springframework.format.")
|| name.startsWith("org.springframework.jca.")
|| name.startsWith("org.springframework.jdbc.")
- || name.startsWith("org.springframework.jms.")
|| name.startsWith("org.springframework.jmx.")
|| name.startsWith("org.springframework.jndi.")
|| name.startsWith("org.springframework.lang.")
@@ -151,6 +150,13 @@ public class AdditionalLibraryIgnoresMatcher<T extends TypeDescription>
return true;
}
+ if (name.startsWith("org.springframework.jms.")) {
+ if (name.startsWith("org.springframework.jms.listener.")) {
+ return false;
+ }
+ return true;
+ }
+
if (name.startsWith("org.springframework.util.")) {
if (name.startsWith("org.springframework.util.concurrent.")) {
return false;

ADD
dd-java-agent/instrumentation/jms/src/latestDepTest/groovy/SpringListenerJMS2Test.groovy
+/*
+ * Copyright 2020, OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import datadog.trace.agent.test.AgentTestRunner
+import listener.Config
+import org.hornetq.jms.client.HornetQMessageConsumer
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import org.springframework.jms.core.JmsTemplate
+import org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter
+
+import javax.jms.ConnectionFactory
+
+import static JMS2Test.consumerTrace
+import static JMS2Test.producerTrace
+
+class SpringListenerJMS2Test extends AgentTestRunner {
+
+ def "receiving message in spring listener generates spans"() {
+ setup:
+ def context = new AnnotationConfigApplicationContext(Config)
+ def factory = context.getBean(ConnectionFactory)
+ def template = new JmsTemplate(factory)
+ template.convertAndSend("someSpringQueue", "a message")
+
+ expect:
+ assertTraces(3) {
+ producerTrace(it, 0, "Queue someSpringQueue")
+ consumerTrace(it, 1, "Queue someSpringQueue", false, HornetQMessageConsumer)
+ consumerTrace(it, 2, "Queue someSpringQueue", true, MessagingMessageListenerAdapter)
+ }
+ }
+}

ADD
dd-java-agent/instrumentation/jms/src/latestDepTest/groovy/listener/Config.groovy
+/*
+ * Copyright 2020, OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package listener
+
+import com.google.common.io.Files
+import org.hornetq.api.core.TransportConfiguration
+import org.hornetq.api.core.client.HornetQClient
+import org.hornetq.api.jms.HornetQJMSClient
+import org.hornetq.api.jms.JMSFactoryType
+import org.hornetq.core.config.CoreQueueConfiguration
+import org.hornetq.core.config.impl.ConfigurationImpl
+import org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory
+import org.hornetq.core.remoting.impl.invm.InVMConnectorFactory
+import org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
+import org.hornetq.core.server.HornetQServers
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.ComponentScan
+import org.springframework.context.annotation.Configuration
+import org.springframework.jms.annotation.EnableJms
+import org.springframework.jms.config.DefaultJmsListenerContainerFactory
+import org.springframework.jms.config.JmsListenerContainerFactory
+
+import javax.jms.ConnectionFactory
+
+@Configuration
+@ComponentScan
+@EnableJms
+class Config {
+
+ @Bean
+ ConnectionFactory connectionFactory() {
+ def tempDir = Files.createTempDir()
+ tempDir.deleteOnExit()
+
+ org.hornetq.core.config.Configuration config = new ConfigurationImpl()
+ config.bindingsDirectory = tempDir.path
+ config.journalDirectory = tempDir.path
+ config.createBindingsDir = false
+ config.createJournalDir = false
+ config.securityEnabled = false
+ config.persistenceEnabled = false
+ config.setQueueConfigurations([new CoreQueueConfiguration("someQueue", "someQueue", null, true)])
+ config.setAcceptorConfigurations([new TransportConfiguration(NettyAcceptorFactory.name),
+ new TransportConfiguration(InVMAcceptorFactory.name)].toSet())
+
+ HornetQServers.newHornetQServer(config).start()
+
+ def serverLocator = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration(InVMConnectorFactory.name))
+ def sf = serverLocator.createSessionFactory()
+ def clientSession = sf.createSession(false, false, false)
+ clientSession.createQueue("jms.queue.someSpringQueue", "jms.queue.someSpringQueue", true)
+ clientSession.close()
+ sf.close()
+ serverLocator.close()
+
+ return HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF,
+ new TransportConfiguration(InVMConnectorFactory.name))
+ }
+
+ @Bean
+ JmsListenerContainerFactory<?> containerFactory(ConnectionFactory connectionFactory) {
+ DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory()
+ factory.setConnectionFactory(connectionFactory)
+ return factory
+ }
+}

ADD
dd-java-agent/instrumentation/jms/src/latestDepTest/groovy/listener/TestListener.groovy
+/*
+ * Copyright 2020, OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package listener
+
+import org.springframework.jms.annotation.JmsListener
+import org.springframework.stereotype.Component
+
+@Component
+class TestListener {
+
+ @JmsListener(destination = "someSpringQueue", containerFactory = "containerFactory")
+ void receiveMessage(String message) {
+ println "received: " + message
+ }
+}

ADD
dd-java-agent/instrumentation/jms/src/test/groovy/SpringListenerJMS1Test.groovy
+/*
+ * Copyright 2020, OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import datadog.trace.agent.test.AgentTestRunner
+import listener.Config
+import org.apache.activemq.ActiveMQMessageConsumer
+import org.apache.activemq.junit.EmbeddedActiveMQBroker
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import org.springframework.jms.core.JmsTemplate
+import org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter
+
+import javax.jms.ConnectionFactory
+
+import static JMS1Test.consumerTrace
+import static JMS1Test.producerTrace
+
+class SpringListenerJMS1Test extends AgentTestRunner {
+
+ def "receiving message in spring listener generates spans"() {
+ setup:
+ def context = new AnnotationConfigApplicationContext(Config)
+ def factory = context.getBean(ConnectionFactory)
+ def template = new JmsTemplate(factory)
+ template.convertAndSend("someSpringQueue", "a message")
+
+ expect:
+ assertTraces(3) {
+ producerTrace(it, 0, "Queue someSpringQueue")
+ consumerTrace(it, 1, "Queue someSpringQueue", false, ActiveMQMessageConsumer)
+ consumerTrace(it, 2, "Queue someSpringQueue", true, MessagingMessageListenerAdapter)
+ }
+
+ cleanup:
+ context.getBean(EmbeddedActiveMQBroker).stop()
+ }
+}

ADD
dd-java-agent/instrumentation/jms/src/test/groovy/listener/Config.groovy
+/*
+ * Copyright 2020, OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package listener
+
+import org.apache.activemq.junit.EmbeddedActiveMQBroker
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.ComponentScan
+import org.springframework.context.annotation.Configuration
+import org.springframework.jms.annotation.EnableJms
+import org.springframework.jms.config.DefaultJmsListenerContainerFactory
+import org.springframework.jms.config.JmsListenerContainerFactory
+
+import javax.jms.ConnectionFactory
+
+@Configuration
+@ComponentScan
+@EnableJms
+class Config {
+
+ @Bean
+ EmbeddedActiveMQBroker broker() {
+ def broker = new EmbeddedActiveMQBroker()
+ broker.start()
+ return broker
+ }
+
+ @Bean
+ ConnectionFactory connectionFactory(EmbeddedActiveMQBroker broker) {
+ return broker.createConnectionFactory()
+ }
+
+ @Bean
+ JmsListenerContainerFactory<?> containerFactory(ConnectionFactory connectionFactory) {
+ DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory()
+ factory.setConnectionFactory(connectionFactory)
+ return factory
+ }
+}

ADD
dd-java-agent/instrumentation/jms/src/test/groovy/listener/TestListener.groovy
+/*
+ * Copyright 2020, OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package listener
+
+import org.springframework.jms.annotation.JmsListener
+import org.springframework.stereotype.Component
+
+@Component
+class TestListener {
+
+ @JmsListener(destination = "someSpringQueue", containerFactory = "containerFactory")
+ void receiveMessage(String message) {
+ println "received: " + message
+ }
+}

Fix for Spring JMS listeners