@Override public ScopedSpan annotate(String value) { state.annotate(clock.currentTimeMicroseconds(), value); return this; }
@Override public SpanCustomizer annotate(String value) { long timestamp = clock.currentTimeMicroseconds(); synchronized (state) { state.annotate(timestamp, value); } return this; }
@Override public Span start() { return start(clock.currentTimeMicroseconds()); }
@Override public void finish() { finish(clock.currentTimeMicroseconds()); }
@Override public Span annotate(String value) { return annotate(clock.currentTimeMicroseconds(), value); }
@Benchmark @Group("no_contention") @GroupThreads(1) public long no_contention_clock_jre9() { return jre9Clock.currentTimeMicroseconds(); }
@Benchmark @Group("no_contention") @GroupThreads(1) public long no_contention_clock_jre7() { return jre7Clock.currentTimeMicroseconds(); }
@Benchmark @Group("mild_contention") @GroupThreads(2) public long mild_contention_clock_jre9() { return jre9Clock.currentTimeMicroseconds(); }
@Benchmark @Group("mild_contention") @GroupThreads(2) public long mild_contention_clock_jre7() { return jre7Clock.currentTimeMicroseconds(); }
@Benchmark @Group("high_contention") @GroupThreads(8) public long high_contention_clock_jre7() { return jre7Clock.currentTimeMicroseconds(); }
@Benchmark @Group("high_contention") @GroupThreads(8) public long high_contention_clock_jre9() { return jre9Clock.currentTimeMicroseconds(); }
@Override public void finish() { scope.close(); if (!pendingSpans.remove(context)) return; // don't double-report state.finishTimestamp(clock.currentTimeMicroseconds()); finishedSpanHandler.handle(context, state); }
/** Reports spans orphaned by garbage collection. */ void reportOrphanedSpans() { RealKey contextKey; // This is called on critical path of unrelated traced operations. If we have orphaned spans, be // careful to not penalize the performance of the caller. It is better to cache time when // flushing a span than hurt performance of unrelated operations by calling // currentTimeMicroseconds N times long flushTime = 0L; boolean noop = zipkinHandler == FinishedSpanHandler.NOOP || this.noop.get(); while ((contextKey = (RealKey) poll()) != null) { PendingSpan value = delegate.remove(contextKey); if (noop || value == null || !contextKey.sampled) continue; if (flushTime == 0L) flushTime = clock.currentTimeMicroseconds(); TraceContext context = InternalPropagation.instance.newTraceContext( InternalPropagation.FLAG_SAMPLED_SET | InternalPropagation.FLAG_SAMPLED, contextKey.traceIdHigh, contextKey.traceId, contextKey.localRootId, 0L, contextKey.spanId, Collections.emptyList() ); value.state.annotate(flushTime, "brave.flush"); try { zipkinHandler.handle(context, value.state); } catch (RuntimeException e) { Platform.get().log("error reporting {0}", context, e); } } }
public PendingSpan getOrCreate(TraceContext context, boolean start) { if (context == null) throw new NullPointerException("context == null"); reportOrphanedSpans(); PendingSpan result = delegate.get(context); if (result != null) return result; MutableSpan data = new MutableSpan(); if (context.shared()) data.setShared(); // save overhead calculating time if the parent is in-progress (usually is) TickClock clock = getClockFromParent(context); if (clock == null) { clock = new TickClock(this.clock.currentTimeMicroseconds(), System.nanoTime()); if (start) data.startTimestamp(clock.baseEpochMicros); } else if (start) { data.startTimestamp(clock.currentTimeMicroseconds()); } PendingSpan newSpan = new PendingSpan(data, clock); PendingSpan previousSpan = delegate.putIfAbsent(new RealKey(context, this), newSpan); if (previousSpan != null) return previousSpan; // lost race return newSpan; }
timestamp = tracing.clock(span.context()).currentTimeMicroseconds(); timestamp = tracing.clock(span.context()).currentTimeMicroseconds();
/** * 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 public void finish() { scope.close(); if (!pendingSpans.remove(context)) return; // don't double-report state.finishTimestamp(clock.currentTimeMicroseconds()); finishedSpanHandler.handle(context, state); }