Use nano time in JMS consumer Instrumenter (#3986)

* Use nano time in JMS consumer Instrumenter

* fix DoNotMockAutoValue
This commit is contained in:
Mateusz Rzeszutek 2021-08-30 18:00:49 +02:00 committed by GitHub
parent 1363e0c093
commit 2b52a8bfe4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 100 additions and 106 deletions

View File

@ -20,6 +20,7 @@ import javax.jms.Queue;
import javax.jms.TemporaryQueue; import javax.jms.TemporaryQueue;
import javax.jms.TemporaryTopic; import javax.jms.TemporaryTopic;
import javax.jms.Topic; import javax.jms.Topic;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
@ -38,6 +39,12 @@ class MessageWithDestinationTest {
@Mock Queue queue; @Mock Queue queue;
@Mock TemporaryQueue temporaryQueue; @Mock TemporaryQueue temporaryQueue;
@Mock Destination destination; @Mock Destination destination;
@Mock Timer timer;
@BeforeEach
void setUp() {
given(timer.startTime()).willReturn(START_TIME);
}
@Test @Test
void shouldCreateMessageWithUnknownDestination() throws JMSException { void shouldCreateMessageWithUnknownDestination() throws JMSException {
@ -46,16 +53,11 @@ class MessageWithDestinationTest {
// when // when
MessageWithDestination result = MessageWithDestination result =
MessageWithDestination.create(message, MessageOperation.SEND, null, START_TIME); MessageWithDestination.create(message, MessageOperation.SEND, null, timer);
// then // then
assertMessage( assertMessage(
MessageOperation.SEND, MessageOperation.SEND, "unknown", "unknown", /* expectedTemporary= */ false, result);
"unknown",
"unknown",
/* expectedTemporary= */ false,
START_TIME,
result);
} }
@Test @Test
@ -65,16 +67,11 @@ class MessageWithDestinationTest {
// when // when
MessageWithDestination result = MessageWithDestination result =
MessageWithDestination.create(message, MessageOperation.SEND, destination, START_TIME); MessageWithDestination.create(message, MessageOperation.SEND, destination, timer);
// then // then
assertMessage( assertMessage(
MessageOperation.SEND, MessageOperation.SEND, "unknown", "unknown", /* expectedTemporary= */ false, result);
"unknown",
"unknown",
/* expectedTemporary= */ false,
START_TIME,
result);
} }
@ParameterizedTest @ParameterizedTest
@ -97,16 +94,11 @@ class MessageWithDestinationTest {
// when // when
MessageWithDestination result = MessageWithDestination result =
MessageWithDestination.create(message, MessageOperation.RECEIVE, null); MessageWithDestination.create(message, MessageOperation.RECEIVE, null, timer);
// then // then
assertMessage( assertMessage(
MessageOperation.RECEIVE, MessageOperation.RECEIVE, "queue", expectedDestinationName, expectedTemporary, result);
"queue",
expectedDestinationName,
expectedTemporary,
null,
result);
} }
@ParameterizedTest @ParameterizedTest
@ -129,16 +121,11 @@ class MessageWithDestinationTest {
// when // when
MessageWithDestination result = MessageWithDestination result =
MessageWithDestination.create(message, MessageOperation.RECEIVE, null); MessageWithDestination.create(message, MessageOperation.RECEIVE, null, timer);
// then // then
assertMessage( assertMessage(
MessageOperation.RECEIVE, MessageOperation.RECEIVE, "topic", expectedDestinationName, expectedTemporary, result);
"topic",
expectedDestinationName,
expectedTemporary,
null,
result);
} }
static Stream<Arguments> destinations() { static Stream<Arguments> destinations() {
@ -154,14 +141,13 @@ class MessageWithDestinationTest {
String expectedDestinationKind, String expectedDestinationKind,
String expectedDestinationName, String expectedDestinationName,
boolean expectedTemporary, boolean expectedTemporary,
Instant expectedStartTime,
MessageWithDestination actual) { MessageWithDestination actual) {
assertSame(message, actual.getMessage()); assertSame(message, actual.message());
assertSame(expectedMessageOperation, actual.getMessageOperation()); assertSame(expectedMessageOperation, actual.messageOperation());
assertEquals(expectedDestinationKind, actual.getDestinationKind()); assertEquals(expectedDestinationKind, actual.destinationKind());
assertEquals(expectedDestinationName, actual.getDestinationName()); assertEquals(expectedDestinationName, actual.destinationName());
assertEquals(expectedTemporary, actual.isTemporaryDestination()); assertEquals(expectedTemporary, actual.isTemporaryDestination());
assertEquals(expectedStartTime, actual.getStartTime()); assertEquals(START_TIME, actual.startTime());
} }
} }

View File

@ -38,6 +38,9 @@ tasks {
val versions: Map<String, String> by project val versions: Map<String, String> by project
dependencies { dependencies {
compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")
compileOnly("javax.jms:jms-api:1.1-rev-1") compileOnly("javax.jms:jms-api:1.1-rev-1")
testImplementation("javax.annotation:javax.annotation-api:1.3.2") testImplementation("javax.annotation:javax.annotation-api:1.3.2")

View File

@ -25,13 +25,13 @@ public class JmsMessageAttributesExtractor
@Nullable @Nullable
@Override @Override
protected String destinationKind(MessageWithDestination messageWithDestination) { protected String destinationKind(MessageWithDestination messageWithDestination) {
return messageWithDestination.getDestinationKind(); return messageWithDestination.destinationKind();
} }
@Nullable @Nullable
@Override @Override
protected String destination(MessageWithDestination messageWithDestination) { protected String destination(MessageWithDestination messageWithDestination) {
return messageWithDestination.getDestinationName(); return messageWithDestination.destinationName();
} }
@Override @Override
@ -61,7 +61,7 @@ public class JmsMessageAttributesExtractor
@Override @Override
protected String conversationId(MessageWithDestination messageWithDestination) { protected String conversationId(MessageWithDestination messageWithDestination) {
try { try {
return messageWithDestination.getMessage().getJMSCorrelationID(); return messageWithDestination.message().getJMSCorrelationID();
} catch (JMSException e) { } catch (JMSException e) {
logger.debug("Failure getting JMS correlation id", e); logger.debug("Failure getting JMS correlation id", e);
return null; return null;
@ -82,14 +82,14 @@ public class JmsMessageAttributesExtractor
@Override @Override
protected MessageOperation operation(MessageWithDestination messageWithDestination) { protected MessageOperation operation(MessageWithDestination messageWithDestination) {
return messageWithDestination.getMessageOperation(); return messageWithDestination.messageOperation();
} }
@Nullable @Nullable
@Override @Override
protected String messageId(MessageWithDestination messageWithDestination, Void unused) { protected String messageId(MessageWithDestination messageWithDestination, Void unused) {
try { try {
return messageWithDestination.getMessage().getJMSMessageID(); return messageWithDestination.message().getJMSMessageID();
} catch (JMSException e) { } catch (JMSException e) {
logger.debug("Failure getting JMS message id", e); logger.debug("Failure getting JMS message id", e);
return null; return null;

View File

@ -17,7 +17,6 @@ import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessageOperat
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import java.time.Instant;
import javax.jms.Message; import javax.jms.Message;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
@ -49,13 +48,13 @@ public class JmsMessageConsumerInstrumentation implements TypeInstrumentation {
public static class ConsumerAdvice { public static class ConsumerAdvice {
@Advice.OnMethodEnter @Advice.OnMethodEnter
public static Instant onEnter() { public static Timer onEnter() {
return Instant.now(); return Timer.start();
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan( public static void stopSpan(
@Advice.Enter Instant startTime, @Advice.Enter Timer timer,
@Advice.Return Message message, @Advice.Return Message message,
@Advice.Thrown Throwable throwable) { @Advice.Thrown Throwable throwable) {
if (message == null) { if (message == null) {
@ -65,7 +64,7 @@ public class JmsMessageConsumerInstrumentation implements TypeInstrumentation {
Context parentContext = Java8BytecodeBridge.currentContext(); Context parentContext = Java8BytecodeBridge.currentContext();
MessageWithDestination request = MessageWithDestination request =
MessageWithDestination.create(message, MessageOperation.RECEIVE, null, startTime); MessageWithDestination.create(message, MessageOperation.RECEIVE, null, timer);
if (consumerInstrumenter().shouldStart(parentContext, request)) { if (consumerInstrumenter().shouldStart(parentContext, request)) {
Context context = consumerInstrumenter().start(parentContext, request); Context context = consumerInstrumenter().start(parentContext, request);

View File

@ -11,7 +11,6 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessagingSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessagingSpanNameExtractor;
import java.time.Instant;
public final class JmsSingletons { public final class JmsSingletons {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jms-1.1"; private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jms-1.1";
@ -37,7 +36,7 @@ public final class JmsSingletons {
otel, INSTRUMENTATION_NAME, spanNameExtractor) otel, INSTRUMENTATION_NAME, spanNameExtractor)
.addAttributesExtractor(attributesExtractor) .addAttributesExtractor(attributesExtractor)
.setTimeExtractors( .setTimeExtractors(
MessageWithDestination::getStartTime, (request, response) -> Instant.now()) MessageWithDestination::startTime, (request, response) -> request.endTime())
.newInstrumenter(SpanKindExtractor.alwaysConsumer()); .newInstrumenter(SpanKindExtractor.alwaysConsumer());
LISTENER_INSTRUMENTER = LISTENER_INSTRUMENTER =
Instrumenter.<MessageWithDestination, Void>newBuilder( Instrumenter.<MessageWithDestination, Void>newBuilder(

View File

@ -14,7 +14,7 @@ public final class MessagePropertyGetter implements TextMapGetter<MessageWithDes
@Override @Override
public Iterable<String> keys(MessageWithDestination message) { public Iterable<String> keys(MessageWithDestination message) {
try { try {
return Collections.list(message.getMessage().getPropertyNames()); return Collections.list(message.message().getPropertyNames());
} catch (JMSException e) { } catch (JMSException e) {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -25,7 +25,7 @@ public final class MessagePropertyGetter implements TextMapGetter<MessageWithDes
String propName = key.replace("-", MessagePropertySetter.DASH); String propName = key.replace("-", MessagePropertySetter.DASH);
final Object value; final Object value;
try { try {
value = carrier.getMessage().getObjectProperty(propName); value = carrier.message().getObjectProperty(propName);
} catch (JMSException e) { } catch (JMSException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }

View File

@ -20,7 +20,7 @@ final class MessagePropertySetter implements TextMapSetter<MessageWithDestinatio
public void set(MessageWithDestination carrier, String key, String value) { public void set(MessageWithDestination carrier, String key, String value) {
String propName = key.replace("-", DASH); String propName = key.replace("-", DASH);
try { try {
carrier.getMessage().setStringProperty(propName, value); carrier.message().setStringProperty(propName, value);
} catch (JMSException e) { } catch (JMSException e) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Failure setting jms property: {}", propName, e); logger.debug("Failure setting jms property: {}", propName, e);

View File

@ -5,6 +5,7 @@
package io.opentelemetry.javaagent.instrumentation.jms; package io.opentelemetry.javaagent.instrumentation.jms;
import com.google.auto.value.AutoValue;
import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessageOperation; import io.opentelemetry.instrumentation.api.instrumenter.messaging.MessageOperation;
import java.time.Instant; import java.time.Instant;
import javax.jms.Destination; import javax.jms.Destination;
@ -14,69 +15,40 @@ import javax.jms.Queue;
import javax.jms.TemporaryQueue; import javax.jms.TemporaryQueue;
import javax.jms.TemporaryTopic; import javax.jms.TemporaryTopic;
import javax.jms.Topic; import javax.jms.Topic;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class MessageWithDestination { @AutoValue
public abstract class MessageWithDestination {
// visible for tests // visible for tests
static final String TIBCO_TMP_PREFIX = "$TMP$"; static final String TIBCO_TMP_PREFIX = "$TMP$";
private final Message message; public abstract Message message();
private final MessageOperation messageOperation;
private final String destinationName;
private final String destinationKind;
private final boolean temporaryDestination;
private final Instant startTime;
private MessageWithDestination( public abstract MessageOperation messageOperation();
Message message,
MessageOperation messageOperation, public abstract String destinationName();
String destinationName,
String destinationKind, public abstract String destinationKind();
boolean temporary,
Instant startTime) { public abstract boolean isTemporaryDestination();
this.message = message;
this.messageOperation = messageOperation; abstract Timer timer();
this.destinationName = destinationName;
this.destinationKind = destinationKind; public Instant startTime() {
this.temporaryDestination = temporary; return timer().startTime();
this.startTime = startTime;
} }
public Message getMessage() { public Instant endTime() {
return message; return timer().endTime();
}
public MessageOperation getMessageOperation() {
return messageOperation;
}
public String getDestinationName() {
return destinationName;
}
public String getDestinationKind() {
return destinationKind;
}
public boolean isTemporaryDestination() {
return temporaryDestination;
}
@Nullable
public Instant getStartTime() {
return startTime;
} }
public static MessageWithDestination create( public static MessageWithDestination create(
Message message, MessageOperation operation, Destination fallbackDestination) { Message message, MessageOperation operation, Destination fallbackDestination) {
return create(message, operation, fallbackDestination, null); return create(message, operation, fallbackDestination, Timer.start());
} }
public static MessageWithDestination create( public static MessageWithDestination create(
Message message, Message message, MessageOperation operation, Destination fallbackDestination, Timer timer) {
MessageOperation operation,
Destination fallbackDestination,
@Nullable Instant startTime) {
Destination jmsDestination = null; Destination jmsDestination = null;
try { try {
jmsDestination = message.getJMSDestination(); jmsDestination = message.getJMSDestination();
@ -88,17 +60,17 @@ public final class MessageWithDestination {
} }
if (jmsDestination instanceof Queue) { if (jmsDestination instanceof Queue) {
return createMessageWithQueue(message, operation, (Queue) jmsDestination, startTime); return createMessageWithQueue(message, operation, (Queue) jmsDestination, timer);
} }
if (jmsDestination instanceof Topic) { if (jmsDestination instanceof Topic) {
return createMessageWithTopic(message, operation, (Topic) jmsDestination, startTime); return createMessageWithTopic(message, operation, (Topic) jmsDestination, timer);
} }
return new MessageWithDestination( return new AutoValue_MessageWithDestination(
message, operation, "unknown", "unknown", /* temporary= */ false, startTime); message, operation, "unknown", "unknown", /* isTemporaryDestination= */ false, timer);
} }
private static MessageWithDestination createMessageWithQueue( private static MessageWithDestination createMessageWithQueue(
Message message, MessageOperation operation, Queue destination, @Nullable Instant startTime) { Message message, MessageOperation operation, Queue destination, Timer timer) {
String queueName; String queueName;
try { try {
queueName = destination.getQueueName(); queueName = destination.getQueueName();
@ -109,11 +81,12 @@ public final class MessageWithDestination {
boolean temporary = boolean temporary =
destination instanceof TemporaryQueue || queueName.startsWith(TIBCO_TMP_PREFIX); destination instanceof TemporaryQueue || queueName.startsWith(TIBCO_TMP_PREFIX);
return new MessageWithDestination(message, operation, queueName, "queue", temporary, startTime); return new AutoValue_MessageWithDestination(
message, operation, queueName, "queue", temporary, timer);
} }
private static MessageWithDestination createMessageWithTopic( private static MessageWithDestination createMessageWithTopic(
Message message, MessageOperation operation, Topic destination, @Nullable Instant startTime) { Message message, MessageOperation operation, Topic destination, Timer timer) {
String topicName; String topicName;
try { try {
topicName = destination.getTopicName(); topicName = destination.getTopicName();
@ -124,6 +97,7 @@ public final class MessageWithDestination {
boolean temporary = boolean temporary =
destination instanceof TemporaryTopic || topicName.startsWith(TIBCO_TMP_PREFIX); destination instanceof TemporaryTopic || topicName.startsWith(TIBCO_TMP_PREFIX);
return new MessageWithDestination(message, operation, topicName, "topic", temporary, startTime); return new AutoValue_MessageWithDestination(
message, operation, topicName, "topic", temporary, timer);
} }
} }

View File

@ -0,0 +1,32 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.jms;
import java.time.Instant;
public final class Timer {
public static Timer start() {
return new Timer(Instant.now(), System.nanoTime());
}
private final Instant startTime;
private final long startNanoTime;
private Timer(Instant startTime, long startNanoTime) {
this.startTime = startTime;
this.startNanoTime = startNanoTime;
}
public Instant startTime() {
return startTime;
}
public Instant endTime() {
long durationNanos = System.nanoTime() - startNanoTime;
return startTime().plusNanos(durationNanos);
}
}