add some JMS attributes
MODIFY
instrumentation/jms-1.1/src/main/java/io/opentelemetry/instrumentation/auto/jms/JMSDecorator.java
instrumentation/jms-1.1/src/main/java/io/opentelemetry/instrumentation/auto/jms/JMSDecorator.java
@@ -18,15 +18,21 @@ package io.opentelemetry.instrumentation.auto.jms;
import io.opentelemetry.OpenTelemetry;
import io.opentelemetry.instrumentation.api.decorator.ClientDecorator;
+import io.opentelemetry.trace.Span;
import io.opentelemetry.trace.Tracer;
+import io.opentelemetry.trace.attributes.SemanticAttributes;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.TemporaryQueue;
import javax.jms.TemporaryTopic;
import javax.jms.Topic;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class JMSDecorator extends ClientDecorator {
+ private static final Logger log = LoggerFactory.getLogger(JMSDecorator.class);
+
public static final JMSDecorator DECORATE = new JMSDecorator();
public static final Tracer TRACER = OpenTelemetry.getTracer("io.opentelemetry.auto.jms-1.1");
@@ -79,4 +85,38 @@ public class JMSDecorator extends ClientDecorator {
}
return "destination";
}
+
+ public void afterStart(Span span, String spanName, Message message) {
+ super.afterStart(span);
+ if (spanName.startsWith("queue/")) {
+ SemanticAttributes.MESSAGING_DESTINATION_KIND.set(span, "queue");
+ SemanticAttributes.MESSAGING_DESTINATION.set(span, spanName.replaceFirst("queue/", ""));
+ } else if (spanName.startsWith("topic/")) {
+ SemanticAttributes.MESSAGING_DESTINATION_KIND.set(span, "topic");
+ SemanticAttributes.MESSAGING_DESTINATION.set(span, spanName.replaceFirst("topic/", ""));
+ }
+ if (spanName.equals("queue/<temporary>") || spanName.equals("topic/<temporary>")) {
+ SemanticAttributes.MESSAGING_TEMP_DESTINATION.set(span, true);
+ }
+
+ if (message != null) {
+ try {
+ String messageID = message.getJMSMessageID();
+ if (messageID != null) {
+ SemanticAttributes.MESSAGING_MESSAGE_ID.set(span, messageID);
+ }
+ } catch (Exception e) {
+ log.debug("Failure getting JMS message id", e);
+ }
+
+ try {
+ String correlationID = message.getJMSCorrelationID();
+ if (correlationID != null) {
+ SemanticAttributes.MESSAGING_CONVERSATION_ID.set(span, correlationID);
+ }
+ } catch (Exception e) {
+ log.debug("Failure getting JMS correlation id", e);
+ }
+ }
+ }
}

MODIFY
instrumentation/jms-1.1/src/main/java/io/opentelemetry/instrumentation/auto/jms/JMSMessageConsumerInstrumentation.java
instrumentation/jms-1.1/src/main/java/io/opentelemetry/instrumentation/auto/jms/JMSMessageConsumerInstrumentation.java
@@ -125,7 +125,7 @@ public final class JMSMessageConsumerInstrumentation extends Instrumenter.Defaul
Span span = spanBuilder.startSpan();
try (Scope scope = currentContextWith(span)) {
- DECORATE.afterStart(span);
+ DECORATE.afterStart(span, spanName, message);
DECORATE.onError(span, throwable);
DECORATE.beforeFinish(span);
span.end();

MODIFY
instrumentation/jms-1.1/src/main/java/io/opentelemetry/instrumentation/auto/jms/JMSMessageListenerInstrumentation.java
instrumentation/jms-1.1/src/main/java/io/opentelemetry/instrumentation/auto/jms/JMSMessageListenerInstrumentation.java
@@ -79,12 +79,12 @@ public final class JMSMessageListenerInstrumentation extends Instrumenter.Defaul
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope onEnter(@Advice.Argument(0) final Message message) {
- Span.Builder spanBuilder =
- TRACER.spanBuilder(DECORATE.spanNameForConsumer(message)).setSpanKind(CONSUMER);
+ final String spanName = DECORATE.spanNameForConsumer(message);
+ Span.Builder spanBuilder = TRACER.spanBuilder(spanName).setSpanKind(CONSUMER);
spanBuilder.setParent(extract(message, GETTER));
Span span = spanBuilder.startSpan();
- DECORATE.afterStart(span);
+ DECORATE.afterStart(span, spanName, message);
return new SpanWithScope(span, currentContextWith(span));
}

MODIFY
instrumentation/jms-1.1/src/main/java/io/opentelemetry/instrumentation/auto/jms/JMSMessageProducerInstrumentation.java
instrumentation/jms-1.1/src/main/java/io/opentelemetry/instrumentation/auto/jms/JMSMessageProducerInstrumentation.java
@@ -105,12 +105,9 @@ public final class JMSMessageProducerInstrumentation extends Instrumenter.Defaul
defaultDestination = null;
}
- Span span =
- TRACER
- .spanBuilder(DECORATE.spanNameForProducer(message, defaultDestination))
- .setSpanKind(PRODUCER)
- .startSpan();
- DECORATE.afterStart(span);
+ final String spanName = DECORATE.spanNameForProducer(message, defaultDestination);
+ Span span = TRACER.spanBuilder(spanName).setSpanKind(PRODUCER).startSpan();
+ DECORATE.afterStart(span, spanName, message);
Context context = withSpan(span, Context.current());
OpenTelemetry.getPropagators().getHttpTextFormat().inject(context, message, SETTER);
@@ -146,12 +143,10 @@ public final class JMSMessageProducerInstrumentation extends Instrumenter.Defaul
return null;
}
- Span span =
- TRACER
- .spanBuilder(DECORATE.spanNameForProducer(message, destination))
- .setSpanKind(PRODUCER)
- .startSpan();
- DECORATE.afterStart(span);
+ final String spanName = DECORATE.spanNameForProducer(message, destination);
+
+ Span span = TRACER.spanBuilder(spanName).setSpanKind(PRODUCER).startSpan();
+ DECORATE.afterStart(span, spanName, message);
Context context = withSpan(span, Context.current());
OpenTelemetry.getPropagators().getHttpTextFormat().inject(context, message, SETTER);

MODIFY
instrumentation/jms-1.1/src/test/groovy/JMS1Test.groovy
instrumentation/jms-1.1/src/test/groovy/JMS1Test.groovy
import io.opentelemetry.auto.test.AgentTestRunner
import io.opentelemetry.auto.test.asserts.TraceAssert
import io.opentelemetry.sdk.trace.data.SpanData
+import io.opentelemetry.trace.attributes.SemanticAttributes
+
import java.util.concurrent.CountDownLatch
import java.util.concurrent.atomic.AtomicReference
import javax.jms.Connection
@@ -65,15 +67,16 @@ class JMS1Test extends AgentTestRunner {
producer.send(message)
TextMessage receivedMessage = consumer.receive()
+ String messageId = receivedMessage.getJMSMessageID()
expect:
receivedMessage.text == messageText
assertTraces(2) {
trace(0, 1) {
- producerSpan(it, 0, expectedSpanName)
+ producerSpan(it, 0, destinationType, destinationName)
}
trace(1, 1) {
- consumerSpan(it, 0, expectedSpanName, false, ActiveMQMessageConsumer, traces[0][0])
+ consumerSpan(it, 0, destinationType, destinationName, messageId, false, ActiveMQMessageConsumer, traces[0][0])
}
}
@@ -82,11 +85,11 @@ class JMS1Test extends AgentTestRunner {
consumer.close()
where:
- destination | expectedSpanName
- session.createQueue("someQueue") | "queue/someQueue"
- session.createTopic("someTopic") | "topic/someTopic"
- session.createTemporaryQueue() | "queue/<temporary>"
- session.createTemporaryTopic() | "topic/<temporary>"
+ destination | destinationType | destinationName
+ session.createQueue("someQueue") | "queue" | "someQueue"
+ session.createTopic("someTopic") | "topic" | "someTopic"
+ session.createTemporaryQueue() | "queue" | "<temporary>"
+ session.createTemporaryTopic() | "topic" | "<temporary>"
}
def "sending to a MessageListener on #expectedSpanName generates a span"() {
@@ -109,8 +112,8 @@ class JMS1Test extends AgentTestRunner {
expect:
assertTraces(1) {
trace(0, 2) {
- producerSpan(it, 0, expectedSpanName)
- consumerSpan(it, 1, expectedSpanName, true, consumer.messageListener.class, span(0))
+ producerSpan(it, 0, destinationType, destinationName)
+ consumerSpan(it, 1, destinationType, destinationName, messageRef.get().getJMSMessageID(), true, consumer.messageListener.class, span(0))
}
}
// This check needs to go after all traces have been accounted for
@@ -121,11 +124,11 @@ class JMS1Test extends AgentTestRunner {
consumer.close()
where:
- destination | expectedSpanName
- session.createQueue("someQueue") | "queue/someQueue"
- session.createTopic("someTopic") | "topic/someTopic"
- session.createTemporaryQueue() | "queue/<temporary>"
- session.createTemporaryTopic() | "topic/<temporary>"
+ destination | destinationType | destinationName
+ session.createQueue("someQueue") | "queue" | "someQueue"
+ session.createTopic("someTopic") | "topic" | "someTopic"
+ session.createTemporaryQueue() | "queue" | "<temporary>"
+ session.createTemporaryTopic() | "topic" | "<temporary>"
}
def "failing to receive message with receiveNoWait on #expectedSpanName works"() {
@@ -141,10 +144,12 @@ class JMS1Test extends AgentTestRunner {
trace(0, 1) { // Consumer trace
span(0) {
parent()
- operationName expectedSpanName
+ operationName destinationType + "/" + destinationName
spanKind CLIENT
errored false
attributes {
+ "${SemanticAttributes.MESSAGING_DESTINATION_KIND.key()}" destinationType
+ "${SemanticAttributes.MESSAGING_DESTINATION.key()}" destinationName
}
}
}
@@ -154,9 +159,9 @@ class JMS1Test extends AgentTestRunner {
consumer.close()
where:
- destination | expectedSpanName
- session.createQueue("someQueue") | "queue/someQueue"
- session.createTopic("someTopic") | "topic/someTopic"
+ destination | destinationType | destinationName
+ session.createQueue("someQueue") | "queue" | "someQueue"
+ session.createTopic("someTopic") | "topic" | "someTopic"
}
def "failing to receive message with wait(timeout) on #expectedSpanName works"() {
@@ -172,10 +177,12 @@ class JMS1Test extends AgentTestRunner {
trace(0, 1) { // Consumer trace
span(0) {
parent()
- operationName expectedSpanName
+ operationName destinationType + "/" + destinationName
spanKind CLIENT
errored false
attributes {
+ "${SemanticAttributes.MESSAGING_DESTINATION_KIND.key()}" destinationType
+ "${SemanticAttributes.MESSAGING_DESTINATION.key()}" destinationName
}
}
}
@@ -185,9 +192,9 @@ class JMS1Test extends AgentTestRunner {
consumer.close()
where:
- destination | expectedSpanName
- session.createQueue("someQueue") | "queue/someQueue"
- session.createTopic("someTopic") | "topic/someTopic"
+ destination | destinationType | destinationName
+ session.createQueue("someQueue") | "queue" | "someQueue"
+ session.createTopic("someTopic") | "topic" | "someTopic"
}
def "sending a read-only message to #expectedSpanName fails"() {
@@ -213,15 +220,21 @@ class JMS1Test extends AgentTestRunner {
// The consumer span will also not be linked to the parent.
assertTraces(2) {
trace(0, 1) {
- producerSpan(it, 0, expectedSpanName)
+ producerSpan(it, 0, destinationType, destinationName)
}
trace(1, 1) {
span(0) {
parent()
- operationName expectedSpanName
+ operationName destinationType + "/" + destinationName
spanKind CLIENT
errored false
attributes {
+ "${SemanticAttributes.MESSAGING_DESTINATION_KIND.key()}" destinationType
+ "${SemanticAttributes.MESSAGING_DESTINATION.key()}" destinationName
+ "${SemanticAttributes.MESSAGING_MESSAGE_ID.key()}" receivedMessage.getJMSMessageID()
+ if (destinationName == "<temporary>") {
+ "${SemanticAttributes.MESSAGING_TEMP_DESTINATION.key()}" true
+ }
}
}
}
@@ -232,27 +245,32 @@ class JMS1Test extends AgentTestRunner {
consumer.close()
where:
- destination | expectedSpanName
- session.createQueue("someQueue") | "queue/someQueue"
- session.createTopic("someTopic") | "topic/someTopic"
- session.createTemporaryQueue() | "queue/<temporary>"
- session.createTemporaryTopic() | "topic/<temporary>"
+ destination | destinationType | destinationName
+ session.createQueue("someQueue") | "queue" | "someQueue"
+ session.createTopic("someTopic") | "topic" | "someTopic"
+ session.createTemporaryQueue() | "queue" | "<temporary>"
+ session.createTemporaryTopic() | "topic" | "<temporary>"
}
- static producerSpan(TraceAssert trace, int index, String expectedSpanName) {
+ static producerSpan(TraceAssert trace, int index, String destinationType, String destinationName) {
trace.span(index) {
- operationName expectedSpanName
+ operationName destinationType + "/" + destinationName
spanKind PRODUCER
errored false
parent()
attributes {
+ "${SemanticAttributes.MESSAGING_DESTINATION_KIND.key()}" destinationType
+ "${SemanticAttributes.MESSAGING_DESTINATION.key()}" destinationName
+ if (destinationName == "<temporary>") {
+ "${SemanticAttributes.MESSAGING_TEMP_DESTINATION.key()}" true
+ }
}
}
}
- static consumerSpan(TraceAssert trace, int index, String expectedSpanName, boolean messageListener, Class origin, Object parentOrLinkedSpan) {
+ static consumerSpan(TraceAssert trace, int index, String destinationType, String destinationName, String messageId, boolean messageListener, Class origin, Object parentOrLinkedSpan) {
trace.span(index) {
- operationName expectedSpanName
+ operationName destinationType + "/" + destinationName
if (messageListener) {
spanKind CONSUMER
childOf((SpanData) parentOrLinkedSpan)
@@ -263,6 +281,16 @@ class JMS1Test extends AgentTestRunner {
}
errored false
attributes {
+ "${SemanticAttributes.MESSAGING_DESTINATION_KIND.key()}" destinationType
+ "${SemanticAttributes.MESSAGING_DESTINATION.key()}" destinationName
+ if (messageId != null) {
+ "${SemanticAttributes.MESSAGING_MESSAGE_ID.key()}" messageId
+ } else {
+ "${SemanticAttributes.MESSAGING_MESSAGE_ID.key()}" String
+ }
+ if (destinationName == "<temporary>") {
+ "${SemanticAttributes.MESSAGING_TEMP_DESTINATION.key()}" true
+ }
}
}
}

MODIFY
instrumentation/jms-1.1/src/test/groovy/SpringListenerJMS1Test.groovy
instrumentation/jms-1.1/src/test/groovy/SpringListenerJMS1Test.groovy
@@ -39,11 +39,11 @@ class SpringListenerJMS1Test extends AgentTestRunner {
expect:
assertTraces(2) {
trace(0, 2) {
- producerSpan(it, 0, "queue/SpringListenerJMS1")
- consumerSpan(it, 1, "queue/SpringListenerJMS1", true, MessagingMessageListenerAdapter, span(0))
+ producerSpan(it, 0, "queue", "SpringListenerJMS1")
+ consumerSpan(it, 1, "queue", "SpringListenerJMS1", null, true, MessagingMessageListenerAdapter, span(0))
}
trace(1, 1) {
- consumerSpan(it, 0, "queue/SpringListenerJMS1", false, ActiveMQMessageConsumer, traces[0][0])
+ consumerSpan(it, 0, "queue", "SpringListenerJMS1", null, false, ActiveMQMessageConsumer, traces[0][0])
}
}

MODIFY
instrumentation/jms-1.1/src/test/groovy/SpringTemplateJMS1Test.groovy
instrumentation/jms-1.1/src/test/groovy/SpringTemplateJMS1Test.groovy
@@ -26,6 +26,7 @@ import javax.jms.Connection
import javax.jms.Session
import javax.jms.TextMessage
import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicReference
import static JMS1Test.consumerSpan
import static JMS1Test.producerSpan
@@ -66,23 +67,25 @@ class SpringTemplateJMS1Test extends AgentTestRunner {
receivedMessage.text == messageText
assertTraces(2) {
trace(0, 1) {
- producerSpan(it, 0, expectedSpanName)
+ producerSpan(it, 0, destinationType, destinationName)
}
trace(1, 1) {
- consumerSpan(it, 0, expectedSpanName, false, ActiveMQMessageConsumer, traces[0][0])
+ consumerSpan(it, 0, destinationType, destinationName, receivedMessage.getJMSMessageID(), false, ActiveMQMessageConsumer, traces[0][0])
}
}
where:
- destination | expectedSpanName
- session.createQueue("SpringTemplateJMS1") | "queue/SpringTemplateJMS1"
+ destination | destinationType | destinationName
+ session.createQueue("SpringTemplateJMS1") | "queue" | "SpringTemplateJMS1"
}
def "send and receive message generates spans"() {
setup:
+ AtomicReference<String> msgId = new AtomicReference<>()
Thread.start {
TextMessage msg = template.receive(destination)
assert msg.text == messageText
+ msgId.set(msg.getJMSMessageID())
template.send(msg.getJMSReplyTo()) {
session -> template.getMessageConverter().toMessage("responded!", session)
@@ -101,21 +104,21 @@ class SpringTemplateJMS1Test extends AgentTestRunner {
receivedMessage.text == "responded!"
assertTraces(4) {
trace(0, 1) {
- producerSpan(it, 0, expectedSpanName)
+ producerSpan(it, 0, destinationType, destinationName)
}
trace(1, 1) {
- consumerSpan(it, 0, expectedSpanName, false, ActiveMQMessageConsumer, traces[0][0])
+ consumerSpan(it, 0, destinationType, destinationName, msgId.get(), false, ActiveMQMessageConsumer, traces[0][0])
}
trace(2, 1) {
- producerSpan(it, 0, "queue/<temporary>") // receive doesn't propagate the trace, so this is a root
+ producerSpan(it, 0, "queue", "<temporary>") // receive doesn't propagate the trace, so this is a root
}
trace(3, 1) {
- consumerSpan(it, 0, "queue/<temporary>", false, ActiveMQMessageConsumer, traces[2][0])
+ consumerSpan(it, 0, "queue", "<temporary>", receivedMessage.getJMSMessageID(), false, ActiveMQMessageConsumer, traces[2][0])
}
}
where:
- destination | expectedSpanName
- session.createQueue("SpringTemplateJMS1") | "queue/SpringTemplateJMS1"
+ destination | destinationType | destinationName
+ session.createQueue("SpringTemplateJMS1") | "queue" | "SpringTemplateJMS1"
}
}

add some JMS attributes (#963)