private Span postProcessSpan(brave.Span span) { if (span == null || span.isNoop()) { return NoOpTracing.NoOpSpan.INSTANCE; } return new BraveSpan(span.kind(brave.Span.Kind.CLIENT), this.tracingOptions); } }
@Override void parseRequest(Req request, Span span) { span.kind(Span.Kind.SERVER); adapter.parseClientIpAndPort(request, span); parser.request(adapter, request, span.customizer()); }
void setConsumerSpan(String topic, Span span) { span.name("poll").kind(Span.Kind.CONSUMER).tag(KafkaTags.KAFKA_TOPIC_TAG, topic); if (remoteServiceName != null) span.remoteServiceName(remoteServiceName); } }
@Override void parseRequest(Req request, Span span) { span.kind(Span.Kind.CLIENT); if (serverName != null) span.remoteServiceName(serverName); parser.request(adapter, request, span.customizer()); }
/** * Uses {@link ThreadLocalSpan} as there's no attribute namespace shared between callbacks, but * all callbacks happen on the same thread. * * <p>Uses {@link ThreadLocalSpan#CURRENT_TRACER} and this interceptor initializes before * tracing. */ @Override public <T extends Resultset> T preProcess(Supplier<String> sqlSupplier, Query interceptedQuery) { // Gets the next span (and places it in scope) so code between here and postProcess can read it Span span = ThreadLocalSpan.CURRENT_TRACER.next(); if (span == null || span.isNoop()) return null; String sql = sqlSupplier.get(); int spaceIndex = sql.indexOf(' '); // Allow span names of single-word statements like COMMIT span.kind(Span.Kind.CLIENT).name(spaceIndex == -1 ? sql : sql.substring(0, spaceIndex)); span.tag("sql.query", sql); parseServerIpAndPort(connection, span); span.start(); return null; }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { if (!(msg instanceof HttpRequest)) { ctx.fireChannelRead(msg); // superclass does not throw return; } HttpRequest request = (HttpRequest) msg; Span span = nextSpan(extractor.extract(request.headers()), request).kind(Span.Kind.SERVER); ctx.channel().attr(NettyHttpTracing.SPAN_ATTRIBUTE).set(span); SpanInScope spanInScope = tracer.withSpanInScope(span); ctx.channel().attr(NettyHttpTracing.SPAN_IN_SCOPE_ATTRIBUTE).set(spanInScope); // Place the span in scope so that downstream code can read trace IDs try { if (!span.isNoop()) { parseChannelAddress(ctx, request, span); parser.request(adapter, request, span.customizer()); span.start(); } ctx.fireChannelRead(msg); spanInScope.close(); } catch (RuntimeException | Error e) { spanInScope.close(); span.error(e).finish(); // the request abended, so finish the span; throw e; } }
/** * Uses {@link ThreadLocalSpan} as there's no attribute namespace shared between callbacks, but * all callbacks happen on the same thread. * * <p>Uses {@link ThreadLocalSpan#CURRENT_TRACER} and this interceptor initializes before tracing. */ @Override public void onBeforeAnyExecute(StatementInformation info) { String sql = includeParameterValues ? info.getSqlWithValues() : info.getSql(); // don't start a span unless there is SQL as we cannot choose a relevant name without it if (sql == null || sql.isEmpty()) return; // Gets the next span (and places it in scope) so code between here and postProcess can read it Span span = ThreadLocalSpan.CURRENT_TRACER.next(); if (span == null || span.isNoop()) return; span.kind(Span.Kind.CLIENT).name(sql.substring(0, sql.indexOf(' '))); span.tag("sql.query", sql); parseServerIpAndPort(info.getConnectionInformation().getConnection(), span); span.start(); }
/** * Uses {@link ThreadLocalSpan} as there's no attribute namespace shared between callbacks, but * all callbacks happen on the same thread. * * <p>Uses {@link ThreadLocalSpan#CURRENT_TRACER} and this interceptor initializes before * tracing. */ @Override public <T extends Resultset> T preProcess(String sql, Statement interceptedStatement) { // Gets the next span (and places it in scope) so code between here and postProcess can read it Span span = ThreadLocalSpan.CURRENT_TRACER.next(); if (span == null || span.isNoop()) return null; // When running a prepared statement, sql will be null and we must fetch the sql from the statement itself if (interceptedStatement instanceof PreparedStatement) { sql = ((PreparedStatement) interceptedStatement).getPreparedSql(); } int spaceIndex = sql.indexOf(' '); // Allow span names of single-word statements like COMMIT span.kind(Span.Kind.CLIENT).name(spaceIndex == -1 ? sql : sql.substring(0, spaceIndex)); span.tag("sql.query", sql); parseServerIpAndPort(connection, span); span.start(); return null; }
/** * Uses {@link ThreadLocalSpan} as there's no attribute namespace shared between callbacks, but * all callbacks happen on the same thread. * * <p>Uses {@link ThreadLocalSpan#CURRENT_TRACER} and this interceptor initializes before * tracing. */ @Override public ResultSetInternalMethods preProcess(String sql, Statement interceptedStatement, Connection connection) { // Gets the next span (and places it in scope) so code between here and postProcess can read it Span span = ThreadLocalSpan.CURRENT_TRACER.next(); if (span == null || span.isNoop()) return null; // When running a prepared statement, sql will be null and we must fetch the sql from the statement itself if (interceptedStatement instanceof PreparedStatement) { sql = ((PreparedStatement) interceptedStatement).getPreparedSql(); } int spaceIndex = sql.indexOf(' '); // Allow span names of single-word statements like COMMIT span.kind(Span.Kind.CLIENT).name(spaceIndex == -1 ? sql : sql.substring(0, spaceIndex)); span.tag("sql.query", sql); parseServerIpAndPort(connection, span); span.start(); return null; }
void setConsumerSpan(Span span, MessageProperties properties) { span.name("next-message").kind(CONSUMER); maybeTag(span, RABBIT_EXCHANGE, properties.getReceivedExchange()); maybeTag(span, RABBIT_ROUTING_KEY, properties.getReceivedRoutingKey()); maybeTag(span, RABBIT_QUEUE, properties.getConsumerQueue()); if (remoteServiceName != null) span.remoteServiceName(remoteServiceName); }
/** * This starts a consumer span as a child of the incoming message or the current trace * context, placing it in scope until the receive completes. */ @Override public Message<?> postReceive(Message<?> message, MessageChannel channel) { if (emptyMessage(message)) { return message; } MessageHeaderAccessor headers = mutableHeaderAccessor(message); TraceContextOrSamplingFlags extracted = this.extractor.extract(headers); Span span = this.threadLocalSpan.next(extracted); MessageHeaderPropagation.removeAnyTraceHeaders(headers, this.tracing.propagation().keys()); this.injector.inject(span.context(), headers); if (!span.isNoop()) { span.kind(Span.Kind.CONSUMER).name("receive").start(); span.remoteServiceName(REMOTE_SERVICE_NAME); addTags(message, span, channel); } if (log.isDebugEnabled()) { log.debug("Created a new span in post receive " + span); } headers.setImmutable(); return new GenericMessage<>(message.getPayload(), headers.getMessageHeaders()); }
/** * Starts and propagates {@link Span.Kind#PRODUCER} span for each message sent. */ @Override public Message<?> preSend(Message<?> message, MessageChannel channel) { if (emptyMessage(message)) { return message; } Message<?> retrievedMessage = getMessage(message); MessageHeaderAccessor headers = mutableHeaderAccessor(retrievedMessage); TraceContextOrSamplingFlags extracted = this.extractor.extract(headers); Span span = this.threadLocalSpan.next(extracted); MessageHeaderPropagation.removeAnyTraceHeaders(headers, this.tracing.propagation().keys()); this.injector.inject(span.context(), headers); if (!span.isNoop()) { span.kind(Span.Kind.PRODUCER).name("send").start(); span.remoteServiceName(REMOTE_SERVICE_NAME); addTags(message, span, channel); } if (log.isDebugEnabled()) { log.debug("Created a new span in pre send" + span); } Message<?> outputMessage = outputMessage(message, retrievedMessage, headers); if (isDirectChannel(channel)) { beforeHandle(outputMessage, channel, null); } return outputMessage; }
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()); }
Span createAndStartProducerSpan(Destination destination, M message) { TraceContext maybeParent = current.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(extractAndClearMessage(message)); } else { // As JMS is sensitive about write access to headers, we defensively clear even if it seems // upstream would have cleared (because there is a span in scope!). span = tracer.newChild(maybeParent); clearPropagationHeaders(message); } if (!span.isNoop()) { span.kind(Span.Kind.PRODUCER).name("send"); if (destination == null) destination = destination(message); if (destination != null) jmsTracing.tagQueueOrTopic(destination, span); if (remoteServiceName != null) span.remoteServiceName(remoteServiceName); span.start(); } addB3SingleHeader(message, span.context()); return span; }
span.kind(Span.Kind.PRODUCER).name("send"); if (remoteServiceName != null) span.remoteServiceName(remoteServiceName); if (record.key() instanceof String && !"".equals(record.key())) {
@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 <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(final ServerCall<ReqT, RespT> call, final Metadata headers, final ServerCallHandler<ReqT, RespT> next) { TraceContextOrSamplingFlags extracted = extractor.extract(headers); Span span = extracted.context() != null ? tracer.joinSpan(extracted.context()) : tracer.nextSpan(extracted); // If grpc propagation is enabled, make sure we refresh the server method if (grpcPropagationFormatEnabled) { Tags tags = span.context().findExtra(Tags.class); if (tags != null) tags.put(RPC_METHOD, call.getMethodDescriptor().getFullMethodName()); } span.kind(Span.Kind.SERVER); parser.onStart(call, headers, span.customizer()); // startCall invokes user interceptors, so we place the span in scope here ServerCall.Listener<ReqT> result; SpanInScope scope = tracer.withSpanInScope(span); try { // retrolambda can't resolve this try/finally result = next.startCall(new TracingServerCall<>(span, call, parser), headers); } catch (RuntimeException | Error e) { span.error(e); span.finish(); throw e; } finally { scope.close(); } // This ensures the server implementation can see the span in scope return new ScopingServerCallListener<>(tracer, span, result, parser); }
@Override public HttpResponse execute(ClientRequestContext ctx, HttpRequest req) throws Exception { final Span span = tracer.nextSpan(); injector.inject(span.context(), req.headers()); // For no-op spans, we only need to inject into headers and don't set any other attributes. if (span.isNoop()) { return delegate().execute(ctx, req); } final String method = ctx.method().name(); span.kind(Kind.CLIENT).name(method); ctx.log().addListener(log -> SpanContextUtil.startSpan(span, log), RequestLogAvailability.REQUEST_START); // Ensure the trace context propagates to children ctx.onChild(RequestContextCurrentTraceContext::copy); ctx.log().addListener(log -> { SpanTags.logWireSend(span, log.requestFirstBytesTransferredTimeNanos(), log); SpanTags.logWireReceive(span, log.responseFirstBytesTransferredTimeNanos(), log); finishSpan(span, log); }, RequestLogAvailability.COMPLETE); try (SpanInScope ignored = tracer.withSpanInScope(span)) { return delegate().execute(ctx, req); } }
@Override public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception { final TraceContextOrSamplingFlags contextOrFlags = extractor.extract(req.headers()); final Span span = contextOrFlags.context() != null ? tracer.joinSpan(contextOrFlags.context()) : tracer.nextSpan(contextOrFlags); // For no-op spans, nothing special to do. if (span.isNoop()) { return delegate().serve(ctx, req); } final String method = ctx.method().name(); span.kind(Kind.SERVER).name(method); ctx.log().addListener(log -> SpanContextUtil.startSpan(span, log), RequestLogAvailability.REQUEST_START); // Ensure the trace context propagates to children ctx.onChild(RequestContextCurrentTraceContext::copy); ctx.log().addListener(log -> { SpanTags.logWireReceive(span, log.requestFirstBytesTransferredTimeNanos(), log); SpanTags.logWireSend(span, log.responseFirstBytesTransferredTimeNanos(), log); SpanContextUtil.closeSpan(span, log); }, RequestLogAvailability.COMPLETE); try (SpanInScope ignored = tracer.withSpanInScope(span)) { return delegate().serve(ctx, req); } } }