TraceContextOrSamplingFlags extracted = this.extractor.extract(headers);
@Override public void accept(Propagation<?> propagation) { TraceContext.Injector<Map<Object, String>> injector = propagation.injector(Map::put); TraceContext.Extractor<Map<Object, String>> extractor = propagation.extractor(Map::get); TraceContext ctx = TraceContext.newBuilder().traceId(1L).spanId(2L).sampled(false).build(); Map<Object, String> map = new LinkedHashMap<>(); injector.inject(ctx, map); assertThat(extractor.extract(map).context()) .isEqualToIgnoringGivenFields(ctx, "traceIdString", "spanIdString"); } }
@Override public void preSend(Message message) { MessageHeaderAccessor headers = makeMessageHeaderAccessor(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.PRODUCER).name("send " + message.getRequiredHeader(Message.DESTINATION)).start(); addMessageTags(span, message); } }
TraceContextOrSamplingFlags extractAndClearHeaders(Headers headers) { TraceContextOrSamplingFlags extracted = extractor.extract(headers); // clear propagation headers if we were able to extract a span if (!extracted.equals(TraceContextOrSamplingFlags.EMPTY)) { clearHeaders(headers); } return extracted; }
@Override public TraceContextOrSamplingFlags extract(C carrier) { TraceContextOrSamplingFlags result = delegate.extract(carrier); // always allocate in case fields are added late Extra fields = propagation.factory.extraFactory.create(); for (int i = 0, length = propagation.keys.size(); i < length; i++) { String maybeValue = getter.get(carrier, propagation.keys.get(i)); if (maybeValue == null) continue; fields.put(propagation.factory.keyToField[i], maybeValue); } return result.toBuilder().addExtra(fields).build(); } }
injector.inject(span.context(), invocation.getAttachments()); } else { TraceContextOrSamplingFlags extracted = extractor.extract(invocation.getAttachments()); span = extracted.context() != null ? tracer.joinSpan(extracted.context())
/** * 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; }
/** * 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()); }
@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 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; } }
@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); } } }
SpringRabbitTracing(Builder builder) { // intentionally hidden constructor this.tracing = builder.tracing; this.extractor = tracing.propagation().extractor(SpringRabbitPropagation.GETTER); List<String> keyList = builder.tracing.propagation().keys(); // Use a more efficient injector if we are only propagating a single header if (builder.writeB3SingleFormat || keyList.equals(Propagation.B3_SINGLE_STRING.keys())) { TraceContext testExtraction = extractor.extract(B3_SINGLE_TEST_HEADERS).context(); if (!TEST_CONTEXT.equals(testExtraction)) { throw new IllegalArgumentException( "SpringRabbitTracing.Builder.writeB3SingleFormat set, but Tracing.Builder.propagationFactory cannot parse this format!"); } this.injector = SpringRabbitPropagation.B3_SINGLE_INJECTOR; } else { this.injector = tracing.propagation().injector(SpringRabbitPropagation.SETTER); } this.propagationKeys = keyList; this.remoteServiceName = builder.remoteServiceName; Field beforePublishPostProcessorsField = null; try { beforePublishPostProcessorsField = RabbitTemplate.class.getDeclaredField("beforePublishPostProcessors"); beforePublishPostProcessorsField.setAccessible(true); } catch (NoSuchFieldException e) { } this.beforePublishPostProcessorsField = beforePublishPostProcessorsField; }
/** * Use this to create a span for processing the given message. Note: the result has no * name and is not started. * <p> * <p> * This creates a child from identifiers extracted from the message headers, or a new * span if one couldn't be extracted. */ public Span nextSpan(Message<?> message) { MessageHeaderAccessor headers = mutableHeaderAccessor(message); TraceContextOrSamplingFlags extracted = this.extractor.extract(headers); headers.setImmutable(); Span result = this.tracer.nextSpan(extracted); if (extracted.context() == null && !result.isNoop()) { addTags(message, result, null); } if (log.isDebugEnabled()) { log.debug("Created a new span " + result); } return result; }
KafkaTracing(Builder builder) { // intentionally hidden constructor this.tracing = builder.tracing; this.extractor = tracing.propagation().extractor(KafkaPropagation.GETTER); List<String> keyList = builder.tracing.propagation().keys(); // Use a more efficient injector if we are only propagating a single header if (builder.writeB3SingleFormat || keyList.equals(Propagation.B3_SINGLE_STRING.keys())) { TraceContext testExtraction = extractor.extract(B3_SINGLE_TEST_HEADERS).context(); if (!TEST_CONTEXT.equals(testExtraction)) { throw new IllegalArgumentException( "KafkaTracing.Builder.writeB3SingleFormat set, but Tracing.Builder.propagationFactory cannot parse this format!"); } this.injector = KafkaPropagation.B3_SINGLE_INJECTOR; } else { this.injector = tracing.propagation().injector(KafkaPropagation.SETTER); } this.propagationKeys = new LinkedHashSet<>(keyList); this.remoteServiceName = builder.remoteServiceName; }
@Benchmark public TraceContextOrSamplingFlags extract_malformed() { return b3Extractor.extract(incomingMalformed); }
@Benchmark public TraceContextOrSamplingFlags extract_no_extra() { return extraExtractor.extract(incomingNoExtra); }
@Benchmark public TraceContextOrSamplingFlags extract_malformed() { return b3Extractor.extract(incomingMalformed); }
@Benchmark public TraceContextOrSamplingFlags extract_unsampled() { return b3Extractor.extract(incomingNotSampled); }
@Benchmark public TraceContextOrSamplingFlags extract_both() { return bothExtractor.extract(incomingBoth); }
@Override public TraceContextOrSamplingFlags extract(C carrier) { Tags tags = null; if (carrier instanceof Metadata) { tags = extractTags(((Metadata) carrier).get(GRPC_TAGS_BIN)); byte[] bytes = ((Metadata) carrier).get(GRPC_TRACE_BIN); if (bytes != null) { TraceContext maybeContext = TraceContextBinaryFormat.parseBytes(bytes, tags); if (maybeContext != null) return TraceContextOrSamplingFlags.create(maybeContext); } } TraceContextOrSamplingFlags result = delegate.extract(carrier); if (tags == null) return result; return result.toBuilder().addExtra(tags).build(); } }