/** * MethodInterceptor for {@link SimpleMessageListenerContainer.ContainerDelegate#invokeListener(Channel, * Message)} */ @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { Message message = (Message) methodInvocation.getArguments()[1]; TraceContextOrSamplingFlags extracted = springRabbitTracing.extractAndClearHeaders(message); // named for BlockingQueueConsumer.nextMessage, which we can't currently see Span consumerSpan = tracer.nextSpan(extracted); Span listenerSpan = tracer.newChild(consumerSpan.context()); if (!consumerSpan.isNoop()) { setConsumerSpan(consumerSpan, message.getMessageProperties()); // incur timestamp overhead only once long timestamp = tracing.clock(consumerSpan.context()).currentTimeMicroseconds(); consumerSpan.start(timestamp); long consumerFinish = timestamp + 1L; // save a clock reading consumerSpan.finish(consumerFinish); // not using scoped span as we want to start with a pre-configured time listenerSpan.name("on-message").start(consumerFinish); } try (SpanInScope ws = tracer.withSpanInScope(listenerSpan)) { return methodInvocation.proceed(); } catch (Throwable t) { listenerSpan.error(t); throw t; } finally { listenerSpan.finish(); } }
void handleReceive(Message message) { if (message == null || tracing.isNoop()) return; // remove prior propagation headers from the message TraceContextOrSamplingFlags extracted = jmsTracing.extractAndClearMessage(message); Span span = tracer.nextSpan(extracted); if (!span.isNoop()) { span.name("receive").kind(Span.Kind.CONSUMER); Destination destination = destination(message); if (destination != null) jmsTracing.tagQueueOrTopic(destination, span); if (remoteServiceName != null) span.remoteServiceName(remoteServiceName); // incur timestamp overhead only once long timestamp = tracing.clock(span.context()).currentTimeMicroseconds(); span.start(timestamp).finish(timestamp); } jmsTracing.setNextParent(message, span.context()); }
@Override public Message postProcessMessage(Message message) { TraceContext maybeParent = currentTraceContext.get(); // Unlike message consumers, we try current span before trying extraction. This is the proper // order because the span in scope should take precedence over a potentially stale header entry. // // NOTE: Brave instrumentation used properly does not result in stale header entries, as we // always clear message headers after reading. Span span; if (maybeParent == null) { span = tracer.nextSpan(springRabbitTracing.extractAndClearHeaders(message)); } else { // If we have a span in scope assume headers were cleared before span = tracer.newChild(maybeParent); } if (!span.isNoop()) { span.kind(Span.Kind.PRODUCER).name("publish"); if (remoteServiceName != null) span.remoteServiceName(remoteServiceName); // incur timestamp overhead only once long timestamp = tracing.clock(span.context()).currentTimeMicroseconds(); span.start(timestamp).finish(timestamp); } injector.inject(span.context(), message.getMessageProperties()); return message; } }
Span startMessageListenerSpan(Message message) { if (!addConsumerSpan) return jmsTracing.nextSpan(message).name("on-message").start(); TraceContextOrSamplingFlags extracted = jmsTracing.extractAndClearMessage(message); // JMS has no visibility of the incoming message, which incidentally could be local! Span consumerSpan = tracer.nextSpan(extracted).kind(CONSUMER).name("receive"); Span listenerSpan = tracer.newChild(consumerSpan.context()); if (!consumerSpan.isNoop()) { long timestamp = tracing.clock(consumerSpan.context()).currentTimeMicroseconds(); consumerSpan.start(timestamp); if (remoteServiceName != null) consumerSpan.remoteServiceName(remoteServiceName); jmsTracing.tagQueueOrTopic(message, consumerSpan); long consumerFinish = timestamp + 1L; // save a clock reading consumerSpan.finish(consumerFinish); // not using scoped span as we want to start late listenerSpan.name("on-message").start(consumerFinish); } return listenerSpan; } }
@Override long currentTimeMicroseconds(Span span) { return tracing .clock(toTraceContext(InternalSpan.instance.context(span))) .currentTimeMicroseconds(); } }