diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/build.gradle b/dd-java-agent/instrumentation/jms/javax-jms-1.1/build.gradle index 739bc235846..74b9d050a9a 100644 --- a/dd-java-agent/instrumentation/jms/javax-jms-1.1/build.gradle +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/build.gradle @@ -14,6 +14,7 @@ muzzle { } apply from: "$rootDir/gradle/java.gradle" +apply plugin: 'java-test-fixtures' repositories { maven { @@ -33,6 +34,8 @@ tasks.named("latestDepTest", Test) { dependencies { compileOnly group: 'javax.jms', name: 'jms-api', version: '1.1-rev-1' + testFixturesCompileOnly group: 'javax.jms', name: 'jms-api', version: '1.1-rev-1' + testImplementation project(':dd-java-agent:instrumentation:datadog:tracing:trace-annotation') testImplementation group: 'org.apache.activemq.tooling', name: 'activemq-junit', version: '5.14.5' testImplementation group: 'org.apache.activemq', name: 'activemq-pool', version: '5.14.5' diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/JMSDecorator.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/JMSDecorator.java index 87fbfc55fc7..c9dd753b3da 100644 --- a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/JMSDecorator.java +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/JMSDecorator.java @@ -19,10 +19,13 @@ import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; +import javax.jms.MessageProducer; import javax.jms.Queue; +import javax.jms.QueueSender; import javax.jms.TemporaryQueue; import javax.jms.TemporaryTopic; import javax.jms.Topic; +import javax.jms.TopicPublisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -265,6 +268,18 @@ public CharSequence toResourceName(String destinationName, boolean isQueue) { return joiner.apply(destinationName); } + public Destination getDestination(final MessageProducer messageProducer) throws JMSException { + try { + return messageProducer.getDestination(); // >= 1.1 + } catch (AbstractMethodError ignored) { + // <=1.1 getDestination is not available so we need to pay an additional instanceOf + if (messageProducer instanceof QueueSender) { + return ((QueueSender) messageProducer).getQueue(); + } + return ((TopicPublisher) messageProducer).getTopic(); + } + } + public String getDestinationName(Destination destination) { String name = null; try { diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/JMSMessageProducerInstrumentation.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/JMSMessageProducerInstrumentation.java index 972b4382209..3dbfa0579f5 100644 --- a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/JMSMessageProducerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/JMSMessageProducerInstrumentation.java @@ -90,10 +90,10 @@ public static AgentScope beforeSend( // fall-back when producer wasn't created via standard Session.createProducer API if (null != producerState) { resourceName = producerState.getResourceName(); - Destination destination = producer.getDestination(); + Destination destination = PRODUCER_DECORATE.getDestination(producer); destinationName = PRODUCER_DECORATE.getDestinationName(destination); } else { - Destination destination = producer.getDestination(); + Destination destination = PRODUCER_DECORATE.getDestination(producer); destinationName = PRODUCER_DECORATE.getDestinationName(destination); boolean isQueue = PRODUCER_DECORATE.isQueue(destination); resourceName = PRODUCER_DECORATE.toResourceName(destinationName, isQueue); diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/SessionInstrumentation.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/SessionInstrumentation.java index 3f7b095b3b7..8c3ffa48231 100644 --- a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/SessionInstrumentation.java +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/main/java/datadog/trace/instrumentation/jms/SessionInstrumentation.java @@ -114,7 +114,7 @@ public static void bindProducerState( int ackMode; try { ackMode = session.getAcknowledgeMode(); - } catch (Exception ignored) { + } catch (Throwable ignored) { ackMode = Session.AUTO_ACKNOWLEDGE; } sessionState = @@ -155,7 +155,7 @@ public static void bindConsumerState( int ackMode; try { ackMode = session.getAcknowledgeMode(); - } catch (Exception ignored) { + } catch (Throwable ignored) { ackMode = Session.AUTO_ACKNOWLEDGE; } sessionState = diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/test/groovy/JMS1Test.groovy b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/test/groovy/JMS1Test.groovy index f059016bc62..f24b7e8f9ff 100644 --- a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/test/groovy/JMS1Test.groovy +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/test/groovy/JMS1Test.groovy @@ -7,32 +7,32 @@ import datadog.trace.agent.test.naming.VersionedNamingTestBase import datadog.trace.api.Config import datadog.trace.api.DDSpanTypes import datadog.trace.api.Trace -import datadog.trace.api.config.TracerConfig import datadog.trace.api.config.TraceInstrumentationConfig +import datadog.trace.api.config.TracerConfig import datadog.trace.bootstrap.instrumentation.api.InstrumentationTags import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.core.DDSpan -import org.apache.activemq.ActiveMQConnectionFactory -import org.apache.activemq.command.ActiveMQTextMessage -import org.apache.activemq.junit.EmbeddedActiveMQBroker -import spock.lang.Shared - +import java.util.concurrent.CountDownLatch +import java.util.concurrent.atomic.AtomicReference import javax.jms.Connection +import javax.jms.ConnectionFactory import javax.jms.Destination import javax.jms.Message import javax.jms.MessageListener +import javax.jms.Queue import javax.jms.QueueConnection import javax.jms.QueueSession import javax.jms.Session import javax.jms.TemporaryQueue import javax.jms.TemporaryTopic -import javax.jms.Queue -import javax.jms.Topic import javax.jms.TextMessage +import javax.jms.Topic import javax.jms.TopicConnection import javax.jms.TopicSession -import java.util.concurrent.CountDownLatch -import java.util.concurrent.atomic.AtomicReference +import jms10mock.Jms10ConnectionFactory +import org.apache.activemq.command.ActiveMQTextMessage +import org.apache.activemq.junit.EmbeddedActiveMQBroker +import spock.lang.Shared abstract class JMS1Test extends VersionedNamingTestBase { @Shared @@ -69,9 +69,13 @@ abstract class JMS1Test extends VersionedNamingTestBase { true } + def createConnectionFactory() { + broker.createConnectionFactory() + } + def setupSpec() { broker.start() - final ActiveMQConnectionFactory connectionFactory = broker.createConnectionFactory() + final ConnectionFactory connectionFactory = createConnectionFactory() connection = connectionFactory.createConnection() connection.start() @@ -1097,3 +1101,10 @@ class JMS1V1ForkedTest extends JMS1Test { "jms.process" } } + +class JMS10Test extends JMS1V0Test { + @Override + def createConnectionFactory() { + new Jms10ConnectionFactory(super.createConnectionFactory()) + } +} diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10Connection.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10Connection.java new file mode 100644 index 00000000000..0f8721a2b89 --- /dev/null +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10Connection.java @@ -0,0 +1,130 @@ +package jms10mock; + +import javax.jms.Connection; +import javax.jms.ConnectionConsumer; +import javax.jms.ConnectionMetaData; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueSession; +import javax.jms.ServerSessionPool; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicSession; + +/** Wraps a real {@link Connection} but simulates a JMS 1.0 provider. */ +public class Jms10Connection implements QueueConnection, TopicConnection { + private final Connection delegate; + + public Jms10Connection(Connection delegate) { + this.delegate = delegate; + } + + // --- JMS 1.1-only unified Connection method --- + + @Override + public Session createSession(boolean transacted, int acknowledgeMode) throws JMSException { + throw new AbstractMethodError( + "JMS 1.0 provider does not implement createSession(boolean, int) on Connection"); + } + + // --- JMS 1.0 QueueConnection methods --- + + @Override + public QueueSession createQueueSession(boolean transacted, int acknowledgeMode) + throws JMSException { + return new Jms10Session(delegate.createSession(transacted, acknowledgeMode)); + } + + // --- JMS 1.0 TopicConnection methods --- + + @Override + public TopicSession createTopicSession(boolean transacted, int acknowledgeMode) + throws JMSException { + return new Jms10Session(delegate.createSession(transacted, acknowledgeMode)); + } + + // --- Common Connection methods --- + + @Override + public String getClientID() throws JMSException { + return delegate.getClientID(); + } + + @Override + public void setClientID(String clientID) throws JMSException { + delegate.setClientID(clientID); + } + + @Override + public ConnectionMetaData getMetaData() throws JMSException { + return delegate.getMetaData(); + } + + @Override + public ExceptionListener getExceptionListener() throws JMSException { + return delegate.getExceptionListener(); + } + + @Override + public void setExceptionListener(ExceptionListener listener) throws JMSException { + delegate.setExceptionListener(listener); + } + + @Override + public void start() throws JMSException { + delegate.start(); + } + + @Override + public void stop() throws JMSException { + delegate.stop(); + } + + @Override + public void close() throws JMSException { + delegate.close(); + } + + // --- ConnectionConsumer methods — not commonly used, throw for JMS 1.1 unified form --- + + @Override + public ConnectionConsumer createConnectionConsumer( + Destination destination, + String messageSelector, + ServerSessionPool sessionPool, + int maxMessages) + throws JMSException { + throw new AbstractMethodError( + "JMS 1.0 provider does not implement createConnectionConsumer(Destination, ...)"); + } + + @Override + public ConnectionConsumer createConnectionConsumer( + Queue queue, String messageSelector, ServerSessionPool sessionPool, int maxMessages) + throws JMSException { + return delegate.createConnectionConsumer(queue, messageSelector, sessionPool, maxMessages); + } + + @Override + public ConnectionConsumer createConnectionConsumer( + Topic topic, String messageSelector, ServerSessionPool sessionPool, int maxMessages) + throws JMSException { + return delegate.createConnectionConsumer(topic, messageSelector, sessionPool, maxMessages); + } + + @Override + public ConnectionConsumer createDurableConnectionConsumer( + Topic topic, + String subscriptionName, + String messageSelector, + ServerSessionPool sessionPool, + int maxMessages) + throws JMSException { + return delegate.createDurableConnectionConsumer( + topic, subscriptionName, messageSelector, sessionPool, maxMessages); + } +} diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10ConnectionFactory.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10ConnectionFactory.java new file mode 100644 index 00000000000..1660765f731 --- /dev/null +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10ConnectionFactory.java @@ -0,0 +1,61 @@ +package jms10mock; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; + +/** + * Wraps a real {@link ConnectionFactory} but simulates a JMS 1.0 provider. + * + *
In JMS 1.0, clients used the domain-specific {@link QueueConnectionFactory} and {@link + * TopicConnectionFactory} to obtain connections. The unified {@link ConnectionFactory} and its + * {@code createConnection()} methods are JMS 1.1 additions that this wrapper does not support. + */ +public class Jms10ConnectionFactory implements QueueConnectionFactory, TopicConnectionFactory { + private final ConnectionFactory delegate; + + public Jms10ConnectionFactory(ConnectionFactory delegate) { + this.delegate = delegate; + } + + // --- JMS 1.1-only unified ConnectionFactory methods --- + + @Override + public Connection createConnection() throws JMSException { + return delegate.createConnection(); + } + + @Override + public Connection createConnection(String userName, String password) throws JMSException { + return delegate.createConnection(userName, password); + } + + // --- JMS 1.0 QueueConnectionFactory methods --- + @Override + public QueueConnection createQueueConnection() throws JMSException { + return new Jms10Connection(delegate.createConnection()); + } + + @Override + public QueueConnection createQueueConnection(String userName, String password) + throws JMSException { + return new Jms10Connection(delegate.createConnection(userName, password)); + } + + // --- JMS 1.0 TopicConnectionFactory methods --- + + @Override + public TopicConnection createTopicConnection() throws JMSException { + return new Jms10Connection(delegate.createConnection()); + } + + @Override + public TopicConnection createTopicConnection(String userName, String password) + throws JMSException { + return new Jms10Connection(delegate.createConnection(userName, password)); + } +} diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10QueueReceiver.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10QueueReceiver.java new file mode 100644 index 00000000000..92b8f8ec93b --- /dev/null +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10QueueReceiver.java @@ -0,0 +1,59 @@ +package jms10mock; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Queue; +import javax.jms.QueueReceiver; + +/** Wraps a real {@link MessageConsumer} but simulates a JMS 1.0 provider. */ +public class Jms10QueueReceiver implements QueueReceiver { + private final MessageConsumer delegate; + private final Queue queue; + + public Jms10QueueReceiver(MessageConsumer delegate, Queue queue) { + this.delegate = delegate; + this.queue = queue; + } + + @Override + public Queue getQueue() { + return queue; + } + + @Override + public String getMessageSelector() throws JMSException { + return delegate.getMessageSelector(); + } + + @Override + public MessageListener getMessageListener() throws JMSException { + return delegate.getMessageListener(); + } + + @Override + public void setMessageListener(MessageListener listener) throws JMSException { + delegate.setMessageListener(listener); + } + + @Override + public Message receive() throws JMSException { + return delegate.receive(); + } + + @Override + public Message receive(long timeout) throws JMSException { + return delegate.receive(timeout); + } + + @Override + public Message receiveNoWait() throws JMSException { + return delegate.receiveNoWait(); + } + + @Override + public void close() throws JMSException { + delegate.close(); + } +} diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10QueueSender.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10QueueSender.java new file mode 100644 index 00000000000..1f888203483 --- /dev/null +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10QueueSender.java @@ -0,0 +1,124 @@ +package jms10mock; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueSender; + +/** Wraps a real {@link MessageProducer} but simulates a JMS 1.0 provider. */ +public class Jms10QueueSender implements QueueSender { + private final MessageProducer delegate; + private final Queue queue; + + public Jms10QueueSender(MessageProducer delegate, Queue queue) { + this.delegate = delegate; + this.queue = queue; + } + + // --- JMS 1.1-only methods — not present in JMS 1.0 --- + + @Override + public Destination getDestination() { + throw new AbstractMethodError("JMS 1.0 provider does not implement getDestination()"); + } + + @Override + public void send(Destination destination, Message message) throws JMSException { + delegate.send(destination, message); + } + + @Override + public void send( + Destination destination, Message message, int deliveryMode, int priority, long timeToLive) + throws JMSException { + delegate.send(destination, message, deliveryMode, priority, timeToLive); + } + + // --- JMS 1.0 QueueSender methods --- + + @Override + public Queue getQueue() { + return queue; + } + + @Override + public void send(Message message) throws JMSException { + delegate.send(message); + } + + @Override + public void send(Message message, int deliveryMode, int priority, long timeToLive) + throws JMSException { + delegate.send(message, deliveryMode, priority, timeToLive); + } + + @Override + public void send(Queue queue, Message message) throws JMSException { + delegate.send(queue, message); + } + + @Override + public void send(Queue queue, Message message, int deliveryMode, int priority, long timeToLive) + throws JMSException { + delegate.send(queue, message, deliveryMode, priority, timeToLive); + } + + // --- MessageProducer config methods --- + + @Override + public void close() throws JMSException { + delegate.close(); + } + + @Override + public void setDisableMessageID(boolean value) throws JMSException { + delegate.setDisableMessageID(value); + } + + @Override + public boolean getDisableMessageID() throws JMSException { + return delegate.getDisableMessageID(); + } + + @Override + public void setDisableMessageTimestamp(boolean value) throws JMSException { + delegate.setDisableMessageTimestamp(value); + } + + @Override + public boolean getDisableMessageTimestamp() throws JMSException { + return delegate.getDisableMessageTimestamp(); + } + + @Override + public void setDeliveryMode(int deliveryMode) throws JMSException { + delegate.setDeliveryMode(deliveryMode); + } + + @Override + public int getDeliveryMode() throws JMSException { + return delegate.getDeliveryMode(); + } + + @Override + public void setPriority(int defaultPriority) throws JMSException { + delegate.setPriority(defaultPriority); + } + + @Override + public int getPriority() throws JMSException { + return delegate.getPriority(); + } + + @Override + public void setTimeToLive(long timeToLive) throws JMSException { + delegate.setTimeToLive(timeToLive); + } + + @Override + public long getTimeToLive() throws JMSException { + return delegate.getTimeToLive(); + } +} diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10Session.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10Session.java new file mode 100644 index 00000000000..65629319237 --- /dev/null +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10Session.java @@ -0,0 +1,229 @@ +package jms10mock; + +import java.io.Serializable; +import javax.jms.BytesMessage; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.QueueReceiver; +import javax.jms.QueueSender; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.StreamMessage; +import javax.jms.TemporaryQueue; +import javax.jms.TemporaryTopic; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; + +/** Wraps a real {@link Session} but simulates a JMS 1.0 provider. */ +public class Jms10Session implements QueueSession, TopicSession { + private final Session delegate; + + public Jms10Session(Session delegate) { + this.delegate = delegate; + } + + // --- JMS 1.1-only unified Session methods — not present in JMS 1.0 --- + + @Override + public MessageProducer createProducer(Destination destination) throws JMSException { + return delegate.createProducer(destination); + } + + @Override + public MessageConsumer createConsumer(Destination destination) throws JMSException { + return delegate.createConsumer(destination); + } + + @Override + public MessageConsumer createConsumer(Destination destination, String messageSelector) + throws JMSException { + return delegate.createConsumer(destination, messageSelector); + } + + @Override + public MessageConsumer createConsumer( + Destination destination, String messageSelector, boolean noLocal) throws JMSException { + return delegate.createConsumer(destination, messageSelector, noLocal); + } + + // --- JMS 1.0 QueueSession methods --- + + @Override + public Queue createQueue(String queueName) throws JMSException { + return delegate.createQueue(queueName); + } + + @Override + public QueueReceiver createReceiver(Queue queue) throws JMSException { + return new Jms10QueueReceiver(delegate.createConsumer(queue), queue); + } + + @Override + public QueueReceiver createReceiver(Queue queue, String messageSelector) throws JMSException { + return new Jms10QueueReceiver(delegate.createConsumer(queue, messageSelector), queue); + } + + @Override + public QueueSender createSender(Queue queue) throws JMSException { + return new Jms10QueueSender(delegate.createProducer(queue), queue); + } + + @Override + public QueueBrowser createBrowser(Queue queue) throws JMSException { + return delegate.createBrowser(queue); + } + + @Override + public QueueBrowser createBrowser(Queue queue, String messageSelector) throws JMSException { + return delegate.createBrowser(queue, messageSelector); + } + + @Override + public TemporaryQueue createTemporaryQueue() throws JMSException { + return delegate.createTemporaryQueue(); + } + + // --- JMS 1.0 TopicSession methods --- + + @Override + public Topic createTopic(String topicName) throws JMSException { + return delegate.createTopic(topicName); + } + + @Override + public TopicSubscriber createSubscriber(Topic topic) throws JMSException { + return new Jms10TopicSubscriber(delegate.createConsumer(topic), topic, false); + } + + @Override + public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) + throws JMSException { + return new Jms10TopicSubscriber( + delegate.createConsumer(topic, messageSelector, noLocal), topic, noLocal); + } + + @Override + public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException { + return new Jms10TopicSubscriber(delegate.createDurableSubscriber(topic, name), topic, false); + } + + @Override + public TopicSubscriber createDurableSubscriber( + Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException { + return new Jms10TopicSubscriber( + delegate.createDurableSubscriber(topic, name, messageSelector, noLocal), topic, noLocal); + } + + @Override + public TopicPublisher createPublisher(Topic topic) throws JMSException { + return new Jms10TopicPublisher(delegate.createProducer(topic), topic); + } + + @Override + public TemporaryTopic createTemporaryTopic() throws JMSException { + return delegate.createTemporaryTopic(); + } + + @Override + public void unsubscribe(String name) throws JMSException { + delegate.unsubscribe(name); + } + + // --- Common Session methods --- + + @Override + public BytesMessage createBytesMessage() throws JMSException { + return delegate.createBytesMessage(); + } + + @Override + public MapMessage createMapMessage() throws JMSException { + return delegate.createMapMessage(); + } + + @Override + public Message createMessage() throws JMSException { + return delegate.createMessage(); + } + + @Override + public ObjectMessage createObjectMessage() throws JMSException { + return delegate.createObjectMessage(); + } + + @Override + public ObjectMessage createObjectMessage(Serializable object) throws JMSException { + return delegate.createObjectMessage(object); + } + + @Override + public StreamMessage createStreamMessage() throws JMSException { + return delegate.createStreamMessage(); + } + + @Override + public TextMessage createTextMessage() throws JMSException { + return delegate.createTextMessage(); + } + + @Override + public TextMessage createTextMessage(String text) throws JMSException { + return delegate.createTextMessage(text); + } + + @Override + public boolean getTransacted() throws JMSException { + return delegate.getTransacted(); + } + + @Override + public int getAcknowledgeMode() { + throw new AbstractMethodError("JMS 1.0 provider does not implement getAcknowledgeMode()"); + } + + @Override + public void commit() throws JMSException { + delegate.commit(); + } + + @Override + public void rollback() throws JMSException { + delegate.rollback(); + } + + @Override + public void close() throws JMSException { + delegate.close(); + } + + @Override + public void recover() throws JMSException { + delegate.recover(); + } + + @Override + public MessageListener getMessageListener() throws JMSException { + return delegate.getMessageListener(); + } + + @Override + public void setMessageListener(MessageListener listener) throws JMSException { + delegate.setMessageListener(listener); + } + + @Override + public void run() { + delegate.run(); + } +} diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10TopicPublisher.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10TopicPublisher.java new file mode 100644 index 00000000000..6f3c1e38663 --- /dev/null +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10TopicPublisher.java @@ -0,0 +1,137 @@ +package jms10mock; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Topic; +import javax.jms.TopicPublisher; + +/** Wraps a real {@link MessageProducer} but simulates a JMS 1.0 provider. */ +public class Jms10TopicPublisher implements TopicPublisher { + private final MessageProducer delegate; + private final Topic topic; + + public Jms10TopicPublisher(MessageProducer delegate, Topic topic) { + this.delegate = delegate; + this.topic = topic; + } + + // --- JMS 1.1-only methods — not present in JMS 1.0 --- + + @Override + public Destination getDestination() { + throw new AbstractMethodError("JMS 1.0 provider does not implement getDestination()"); + } + + @Override + public void send(Destination destination, Message message) throws JMSException { + delegate.send(destination, message); + } + + @Override + public void send( + Destination destination, Message message, int deliveryMode, int priority, long timeToLive) + throws JMSException { + delegate.send(destination, message, deliveryMode, priority, timeToLive); + } + + // --- JMS 1.0 TopicPublisher methods --- + + @Override + public Topic getTopic() { + return topic; + } + + @Override + public void publish(Message message) throws JMSException { + delegate.send(message); + } + + @Override + public void publish(Message message, int deliveryMode, int priority, long timeToLive) + throws JMSException { + delegate.send(message, deliveryMode, priority, timeToLive); + } + + @Override + public void publish(Topic topic, Message message) throws JMSException { + delegate.send(topic, message); + } + + @Override + public void publish(Topic topic, Message message, int deliveryMode, int priority, long timeToLive) + throws JMSException { + delegate.send(topic, message, deliveryMode, priority, timeToLive); + } + + // --- MessageProducer send methods (also available via publish in 1.0) --- + + @Override + public void send(Message message) throws JMSException { + delegate.send(message); + } + + @Override + public void send(Message message, int deliveryMode, int priority, long timeToLive) + throws JMSException { + delegate.send(message, deliveryMode, priority, timeToLive); + } + + // --- MessageProducer config methods --- + + @Override + public void close() throws JMSException { + delegate.close(); + } + + @Override + public void setDisableMessageID(boolean value) throws JMSException { + delegate.setDisableMessageID(value); + } + + @Override + public boolean getDisableMessageID() throws JMSException { + return delegate.getDisableMessageID(); + } + + @Override + public void setDisableMessageTimestamp(boolean value) throws JMSException { + delegate.setDisableMessageTimestamp(value); + } + + @Override + public boolean getDisableMessageTimestamp() throws JMSException { + return delegate.getDisableMessageTimestamp(); + } + + @Override + public void setDeliveryMode(int deliveryMode) throws JMSException { + delegate.setDeliveryMode(deliveryMode); + } + + @Override + public int getDeliveryMode() throws JMSException { + return delegate.getDeliveryMode(); + } + + @Override + public void setPriority(int defaultPriority) throws JMSException { + delegate.setPriority(defaultPriority); + } + + @Override + public int getPriority() throws JMSException { + return delegate.getPriority(); + } + + @Override + public void setTimeToLive(long timeToLive) throws JMSException { + delegate.setTimeToLive(timeToLive); + } + + @Override + public long getTimeToLive() throws JMSException { + return delegate.getTimeToLive(); + } +} diff --git a/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10TopicSubscriber.java b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10TopicSubscriber.java new file mode 100644 index 00000000000..97ca5ea2343 --- /dev/null +++ b/dd-java-agent/instrumentation/jms/javax-jms-1.1/src/testFixtures/java/jms10mock/Jms10TopicSubscriber.java @@ -0,0 +1,66 @@ +package jms10mock; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +/** Wraps a real {@link MessageConsumer} but simulates a JMS 1.0 provider. */ +public class Jms10TopicSubscriber implements TopicSubscriber { + private final MessageConsumer delegate; + private final Topic topic; + private final boolean noLocal; + + public Jms10TopicSubscriber(MessageConsumer delegate, Topic topic, boolean noLocal) { + this.delegate = delegate; + this.topic = topic; + this.noLocal = noLocal; + } + + @Override + public Topic getTopic() { + return topic; + } + + @Override + public boolean getNoLocal() { + return noLocal; + } + + @Override + public String getMessageSelector() throws JMSException { + return delegate.getMessageSelector(); + } + + @Override + public MessageListener getMessageListener() throws JMSException { + return delegate.getMessageListener(); + } + + @Override + public void setMessageListener(MessageListener listener) throws JMSException { + delegate.setMessageListener(listener); + } + + @Override + public Message receive() throws JMSException { + return delegate.receive(); + } + + @Override + public Message receive(long timeout) throws JMSException { + return delegate.receive(timeout); + } + + @Override + public Message receiveNoWait() throws JMSException { + return delegate.receiveNoWait(); + } + + @Override + public void close() throws JMSException { + delegate.close(); + } +} diff --git a/dd-java-agent/instrumentation/spark/sparkjava-2.3/build.gradle b/dd-java-agent/instrumentation/spark/sparkjava-2.3/build.gradle index d2c1dabe2a2..14ce833d991 100644 --- a/dd-java-agent/instrumentation/spark/sparkjava-2.3/build.gradle +++ b/dd-java-agent/instrumentation/spark/sparkjava-2.3/build.gradle @@ -1,4 +1,3 @@ - // building against 2.3 and testing against 2.4 because JettyHandler is available since 2.4 only muzzle { pass { @@ -22,3 +21,7 @@ dependencies { latestDepTestImplementation group: 'com.sparkjava', name: 'spark-core', version: '+' } + +tasks.withType(Test).configureEach { + jvmArgs += ['-Ddd.trace.enabled=true'] +} diff --git a/dd-java-agent/instrumentation/spark/sparkjava-2.3/gradle.lockfile b/dd-java-agent/instrumentation/spark/sparkjava-2.3/gradle.lockfile deleted file mode 100644 index 03bd65d20d3..00000000000 --- a/dd-java-agent/instrumentation/spark/sparkjava-2.3/gradle.lockfile +++ /dev/null @@ -1,167 +0,0 @@ -# This is a Gradle generated file for dependency locking. -# Manual edits can break the build and are not advised. -# This file is expected to be part of source control. -cafe.cryptography:curve25519-elisabeth:0.1.0=latestDepTestRuntimeClasspath,testRuntimeClasspath -cafe.cryptography:ed25519-elisabeth:0.1.0=latestDepTestRuntimeClasspath,testRuntimeClasspath -ch.qos.logback:logback-classic:1.2.13=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -ch.qos.logback:logback-core:1.2.13=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.blogspot.mydailyjava:weak-lock-free:0.17=buildTimeInstrumentationPlugin,compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq.okhttp3:okhttp:3.12.15=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq.okio:okio:1.17.6=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq:dd-instrument-java:0.0.3=buildTimeInstrumentationPlugin,compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq:dd-javac-plugin-client:0.2.2=buildTimeInstrumentationPlugin,compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq:java-dogstatsd-client:4.4.5=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.datadoghq:sketches-java:0.8.3=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.github.javaparser:javaparser-core:3.25.6=codenarc -com.github.jnr:jffi:1.3.14=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-a64asm:1.0.0=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-constants:0.10.4=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-enxio:0.32.19=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-ffi:2.2.18=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-posix:3.1.21=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-unixsocket:0.38.24=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-x86asm:1.0.2=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.github.spotbugs:spotbugs-annotations:4.9.8=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath -com.github.spotbugs:spotbugs:4.9.8=spotbugs -com.github.stephenc.jcip:jcip-annotations:1.0-1=spotbugs -com.google.auto.service:auto-service-annotations:1.1.1=annotationProcessor,compileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,testAnnotationProcessor,testCompileClasspath -com.google.auto.service:auto-service:1.1.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.auto:auto-common:1.2.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -com.google.code.gson:gson:2.13.2=spotbugs -com.google.errorprone:error_prone_annotations:2.18.0=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.errorprone:error_prone_annotations:2.41.0=spotbugs -com.google.guava:failureaccess:1.0.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.guava:guava:20.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.google.guava:guava:32.0.1-jre=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.j2objc:j2objc-annotations:2.8=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -com.google.re2j:re2j:1.7=latestDepTestRuntimeClasspath,testRuntimeClasspath -com.sparkjava:spark-core:2.3=compileClasspath -com.sparkjava:spark-core:2.4=testCompileClasspath,testRuntimeClasspath -com.sparkjava:spark-core:2.9.4=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -com.squareup.moshi:moshi:1.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.squareup.okhttp3:logging-interceptor:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.squareup.okhttp3:okhttp:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.squareup.okio:okio:1.17.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -com.thoughtworks.qdox:qdox:1.12.1=codenarc -commons-fileupload:commons-fileupload:1.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -commons-io:commons-io:2.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -commons-io:commons-io:2.20.0=spotbugs -de.thetaphi:forbiddenapis:3.10=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -io.leangen.geantyref:geantyref:1.3.16=latestDepTestRuntimeClasspath,testRuntimeClasspath -io.sqreen:libsqreen:17.3.0=latestDepTestRuntimeClasspath,testRuntimeClasspath -javax.servlet:javax.servlet-api:3.1.0=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -jaxen:jaxen:2.0.0=spotbugs -junit:junit:4.13.2=latestDepTestRuntimeClasspath,testRuntimeClasspath -net.bytebuddy:byte-buddy-agent:1.18.8=buildTimeInstrumentationPlugin,compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -net.bytebuddy:byte-buddy:1.18.8=buildTimeInstrumentationPlugin,compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -net.java.dev.jna:jna-platform:5.8.0=latestDepTestRuntimeClasspath,testRuntimeClasspath -net.java.dev.jna:jna:5.8.0=latestDepTestRuntimeClasspath,testRuntimeClasspath -net.sf.saxon:Saxon-HE:12.9=spotbugs -org.apache.ant:ant-antlr:1.10.14=codenarc -org.apache.ant:ant-junit:1.10.14=codenarc -org.apache.bcel:bcel:6.11.0=spotbugs -org.apache.commons:commons-lang3:3.19.0=spotbugs -org.apache.commons:commons-text:1.14.0=spotbugs -org.apache.logging.log4j:log4j-api:2.25.2=spotbugs -org.apache.logging.log4j:log4j-core:2.25.2=spotbugs -org.apiguardian:apiguardian-api:1.1.2=latestDepTestCompileClasspath,testCompileClasspath -org.checkerframework:checker-qual:3.33.0=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor -org.codehaus.groovy:groovy-ant:3.0.23=codenarc -org.codehaus.groovy:groovy-docgenerator:3.0.23=codenarc -org.codehaus.groovy:groovy-groovydoc:3.0.23=codenarc -org.codehaus.groovy:groovy-json:3.0.23=codenarc -org.codehaus.groovy:groovy-json:3.0.25=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-templates:3.0.23=codenarc -org.codehaus.groovy:groovy-xml:3.0.23=codenarc -org.codehaus.groovy:groovy:3.0.23=codenarc -org.codehaus.groovy:groovy:3.0.25=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.codenarc:CodeNarc:3.7.0=codenarc -org.dom4j:dom4j:2.2.0=spotbugs -org.eclipse.jetty.websocket:websocket-api:9.3.2.v20150730=compileClasspath -org.eclipse.jetty.websocket:websocket-api:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty.websocket:websocket-api:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty.websocket:websocket-client:9.3.2.v20150730=compileClasspath -org.eclipse.jetty.websocket:websocket-client:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty.websocket:websocket-client:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty.websocket:websocket-common:9.3.2.v20150730=compileClasspath -org.eclipse.jetty.websocket:websocket-common:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty.websocket:websocket-common:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty.websocket:websocket-server:9.3.2.v20150730=compileClasspath -org.eclipse.jetty.websocket:websocket-server:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty.websocket:websocket-server:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty.websocket:websocket-servlet:9.3.2.v20150730=compileClasspath -org.eclipse.jetty.websocket:websocket-servlet:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty.websocket:websocket-servlet:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-client:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-http:9.3.2.v20150730=compileClasspath -org.eclipse.jetty:jetty-http:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-http:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-io:9.3.2.v20150730=compileClasspath -org.eclipse.jetty:jetty-io:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-io:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-security:9.3.2.v20150730=compileClasspath -org.eclipse.jetty:jetty-security:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-security:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-server:9.3.2.v20150730=compileClasspath -org.eclipse.jetty:jetty-server:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-server:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-servlet:9.3.2.v20150730=compileClasspath -org.eclipse.jetty:jetty-servlet:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-servlet:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-util-ajax:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-util:9.3.2.v20150730=compileClasspath -org.eclipse.jetty:jetty-util:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-util:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-webapp:9.3.2.v20150730=compileClasspath -org.eclipse.jetty:jetty-webapp:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-webapp:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.eclipse.jetty:jetty-xml:9.3.2.v20150730=compileClasspath -org.eclipse.jetty:jetty-xml:9.3.6.v20151106=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-xml:9.4.48.v20220622=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath -org.gmetrics:GMetrics:2.1.0=codenarc -org.hamcrest:hamcrest-core:1.3=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.hamcrest:hamcrest:3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.jctools:jctools-core-jdk11:4.0.6=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.jctools:jctools-core:4.0.6=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-api:5.14.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-engine:5.14.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-params:5.14.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter:5.14.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-commons:1.14.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-engine:1.14.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-launcher:1.14.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-runner:1.14.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-suite-api:1.14.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-suite-commons:1.14.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.junit:junit-bom:5.14.0=spotbugs -org.junit:junit-bom:5.14.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.mockito:mockito-core:4.4.0=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.objenesis:objenesis:3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.opentest4j:opentest4j:1.3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.ow2.asm:asm-analysis:9.7.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.ow2.asm:asm-analysis:9.9=spotbugs -org.ow2.asm:asm-commons:9.9=spotbugs -org.ow2.asm:asm-commons:9.9.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.ow2.asm:asm-tree:9.9=spotbugs -org.ow2.asm:asm-tree:9.9.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.ow2.asm:asm-util:9.7.1=latestDepTestRuntimeClasspath,testRuntimeClasspath -org.ow2.asm:asm-util:9.9=spotbugs -org.ow2.asm:asm:9.9=spotbugs -org.ow2.asm:asm:9.9.1=buildTimeInstrumentationPlugin,compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.slf4j:jcl-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.slf4j:jul-to-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.slf4j:log4j-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.slf4j:slf4j-api:1.7.30=buildTimeInstrumentationPlugin,compileClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath -org.slf4j:slf4j-api:1.7.32=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.slf4j:slf4j-api:2.0.17=spotbugs,spotbugsSlf4j -org.slf4j:slf4j-simple:1.7.12=compileClasspath -org.slf4j:slf4j-simple:2.0.17=spotbugsSlf4j -org.snakeyaml:snakeyaml-engine:2.9=buildTimeInstrumentationPlugin,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -org.spockframework:spock-bom:2.4-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.spockframework:spock-core:2.4-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.tabletest:tabletest-junit:1.2.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.tabletest:tabletest-parser:1.2.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath -org.xmlresolver:xmlresolver:5.3.3=spotbugs -empty=spotbugsPlugins diff --git a/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/main/java/datadog/trace/instrumentation/sparkjava/RoutesInstrumentation.java b/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/main/java/datadog/trace/instrumentation/sparkjava/RoutesInstrumentation.java index b4dbe6e5c02..3534719bea7 100644 --- a/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/main/java/datadog/trace/instrumentation/sparkjava/RoutesInstrumentation.java +++ b/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/main/java/datadog/trace/instrumentation/sparkjava/RoutesInstrumentation.java @@ -3,6 +3,8 @@ import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.decorator.http.HttpResourceDecorator.HTTP_RESOURCE_DECORATOR; +import static datadog.trace.instrumentation.sparkjava.SparkJavaDecorator.DECORATE; +import static datadog.trace.instrumentation.sparkjava.SparkJavaDecorator.SPARK_JAVA; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -11,6 +13,7 @@ import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.Tags; import net.bytebuddy.asm.Advice; import spark.route.HttpMethod; import spark.routematch.RouteMatch; @@ -20,12 +23,12 @@ public class RoutesInstrumentation extends InstrumenterModule.Tracing implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { public RoutesInstrumentation() { - super("sparkjava", "sparkjava-2.4"); + super("sparkjava", "sparkjava-2.3"); } @Override - public boolean defaultEnabled() { - return false; + public String[] helperClassNames() { + return new String[] {packageName + ".SparkJavaDecorator"}; } @Override @@ -52,6 +55,8 @@ public static void routeMatchEnricher( final AgentSpan span = activeSpan(); if (span != null && routeMatch != null) { HTTP_RESOURCE_DECORATOR.withRoute(span, method.name(), routeMatch.getMatchUri()); + span.setSpanName(DECORATE.spanName()); + span.setTag(Tags.COMPONENT, SPARK_JAVA); } } } diff --git a/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/main/java/datadog/trace/instrumentation/sparkjava/SparkJavaDecorator.java b/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/main/java/datadog/trace/instrumentation/sparkjava/SparkJavaDecorator.java new file mode 100644 index 00000000000..4657f85ccad --- /dev/null +++ b/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/main/java/datadog/trace/instrumentation/sparkjava/SparkJavaDecorator.java @@ -0,0 +1,31 @@ +package datadog.trace.instrumentation.sparkjava; + +import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; +import datadog.trace.bootstrap.instrumentation.decorator.BaseDecorator; + +public class SparkJavaDecorator extends BaseDecorator { + + public static final SparkJavaDecorator DECORATE = new SparkJavaDecorator(); + + public static final CharSequence SPARK_JAVA = UTF8BytesString.create("spark-java"); + public static final CharSequence SPARK_REQUEST = UTF8BytesString.create("spark.request"); + + @Override + protected String[] instrumentationNames() { + return new String[] {"sparkjava"}; + } + + @Override + protected CharSequence spanType() { + return "web"; + } + + @Override + protected CharSequence component() { + return SPARK_JAVA; + } + + public CharSequence spanName() { + return SPARK_REQUEST; + } +} diff --git a/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/test/groovy/SparkJavaBasedTest.groovy b/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/test/groovy/SparkJavaBasedTest.groovy deleted file mode 100644 index 2c33e8d745b..00000000000 --- a/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/test/groovy/SparkJavaBasedTest.groovy +++ /dev/null @@ -1,73 +0,0 @@ -import datadog.trace.agent.test.InstrumentationSpecification -import datadog.trace.agent.test.utils.OkHttpUtils -import datadog.trace.agent.test.utils.PortUtils -import datadog.trace.api.DDSpanTypes -import datadog.trace.bootstrap.instrumentation.api.Tags -import okhttp3.OkHttpClient -import okhttp3.Request -import spark.Spark -import spock.lang.Shared - -class SparkJavaBasedTest extends InstrumentationSpecification { - - @Override - void configurePreAgent() { - super.configurePreAgent() - injectSysConfig("dd.integration.jetty.enabled", "true") - injectSysConfig("dd.integration.sparkjava.enabled", "true") - } - - @Shared - int port - - OkHttpClient client = OkHttpUtils.client() - - def setupSpec() { - port = PortUtils.randomOpenPort() - TestSparkJavaApplication.initSpark(port) - } - - def cleanupSpec() { - Spark.stop() - } - - def "generates spans"() { - setup: - def request = new Request.Builder() - .url("http://localhost:$port/param/asdf1234") - .get() - .build() - def response = client.newCall(request).execute() - - expect: - port != 0 - response.body().string() == "Hello asdf1234" - - assertTraces(1) { - trace(1) { - span { - operationName "servlet.request" - resourceName "GET /param/:param" - spanType DDSpanTypes.HTTP_SERVER - errored false - parent() - tags { - "$Tags.COMPONENT" "jetty-server" - "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOST_IPV4" "127.0.0.1" - "$Tags.PEER_PORT" Integer - "$Tags.HTTP_URL" "http://localhost:$port/param/asdf1234" - "$Tags.HTTP_HOSTNAME" "localhost" - "$Tags.HTTP_METHOD" "GET" - "$Tags.HTTP_STATUS" 200 - "$Tags.HTTP_ROUTE" String - "$Tags.HTTP_USER_AGENT" String - "$Tags.HTTP_CLIENT_IP" "127.0.0.1" - "$Tags.NETWORK_CLIENT_IP" "127.0.0.1" - defaultTags() - } - } - } - } - } -} diff --git a/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/test/java/TestSparkJavaApplication.java b/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/test/java/TestSparkJavaApplication.java deleted file mode 100644 index 93f904c7206..00000000000 --- a/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/test/java/TestSparkJavaApplication.java +++ /dev/null @@ -1,19 +0,0 @@ -import spark.Spark; - -public class TestSparkJavaApplication { - - public static void initSpark(final int port) { - Spark.port(port); - Spark.get("/", (req, res) -> "Hello World"); - - Spark.get("/param/:param", (req, res) -> "Hello " + req.params("param")); - - Spark.get( - "/exception/:param", - (req, res) -> { - throw new RuntimeException(req.params("param")); - }); - - Spark.awaitInitialization(); - } -} diff --git a/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/test/java/datadog/trace/instrumentation/sparkjava/SparkJavaForkedTest.java b/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/test/java/datadog/trace/instrumentation/sparkjava/SparkJavaForkedTest.java new file mode 100644 index 00000000000..9b5de61b72b --- /dev/null +++ b/dd-java-agent/instrumentation/spark/sparkjava-2.3/src/test/java/datadog/trace/instrumentation/sparkjava/SparkJavaForkedTest.java @@ -0,0 +1,226 @@ +package datadog.trace.instrumentation.sparkjava; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import datadog.trace.agent.test.AbstractInstrumentationTest; +import datadog.trace.agent.test.utils.PortUtils; +import datadog.trace.core.DDSpan; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeoutException; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import spark.Request; +import spark.Response; +import spark.Route; +import spark.Spark; + +/** + * Forked test for the SparkJava 2.x instrumentation, running in an isolated JVM. This validates + * that the {@link RoutesInstrumentation} loads and enriches Jetty server spans correctly when the + * agent starts from scratch — no leftover state from other test classes. + * + *
This test focuses on the core enrichment contract: when a request matches a SparkJava route, + * the server span gets operation name {@code spark.request}, component {@code spark-java}, and the + * resource name / http.route reflect the parameterized route pattern. + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class SparkJavaForkedTest extends AbstractInstrumentationTest { + + private int actualPort; + + @BeforeAll + void setupServer() { + actualPort = PortUtils.randomOpenPort(); + Spark.port(actualPort); + + Spark.get( + "/ping", + new Route() { + @Override + public Object handle(Request request, Response response) { + response.type("text/plain"); + return "pong"; + } + }); + + Spark.get( + "/items/:id", + new Route() { + @Override + public Object handle(Request request, Response response) { + response.type("application/json"); + return "{\"id\": \"" + request.params(":id") + "\"}"; + } + }); + + Spark.get( + "/fail", + new Route() { + @Override + public Object handle(Request request, Response response) { + throw new RuntimeException("Forked test error"); + } + }); + + Spark.awaitInitialization(); + } + + @AfterAll + void tearDownServer() throws InterruptedException { + Spark.stop(); + Thread.sleep(500); + } + + @Test + void simpleRouteEnrichesServerSpan() throws InterruptedException, TimeoutException { + httpGet("/ping"); + + DDSpan serverSpan = waitForServerSpan(); + assertServerSpan(serverSpan, "GET", "/ping", 200, false); + } + + @Test + void parameterizedRoutePatternInResourceName() throws InterruptedException, TimeoutException { + httpGet("/items/42"); + + DDSpan serverSpan = waitForServerSpan(); + assertServerSpan(serverSpan, "GET", "/items/:id", 200, false); + } + + @Test + void errorRouteProducesErrorSpan() throws InterruptedException, TimeoutException { + httpGet("/fail"); + + DDSpan serverSpan = waitForServerSpan(); + assertServerSpan(serverSpan, "GET", "/fail", 500, true); + } + + // --------------------------------------------------------------- + // Helper methods + // --------------------------------------------------------------- + + /** + * Validates the complete structure of a server span, covering both SparkJava enrichment and the + * underlying Jetty server span baseline. This single-point-of-assertion prevents regressions when + * new required tags are added. + * + *
SparkJava enrichment (set by {@link RoutesInstrumentation}): + * + *
Jetty baseline (set by the Jetty server instrumentation): + * + *
SparkJava runs on an embedded Jetty server. The Jetty instrumentation creates the server span, + * and the SparkJava {@link RoutesInstrumentation} enriches it with route information from the + * {@code Routes.find()} method. + * + *
Acceptance criteria verified by these tests: + * + *
SparkJava enrichment (set by {@link RoutesInstrumentation}): + * + *
Jetty baseline (set by the Jetty server instrumentation): + * + *