void noticesDifferentSpanId(Scope scope) { TraceContext differentSpanId = context.toBuilder().spanId(context.spanId() + 1L).build(); try (Scope scope2 = currentTraceContext.maybeScope(differentSpanId)) { assertThat(scope2).isNotEqualTo(Scope.NOOP); assertThat(currentTraceContext.get()) .isEqualTo(differentSpanId); verifyImplicitContext(differentSpanId); } finally { scope.close(); } }
/** * Ensures the specified {@link Tracing} uses a {@link RequestContextCurrentTraceContext}. * * @throws IllegalStateException if {@code tracing} does not use {@link RequestContextCurrentTraceContext} */ public static void ensureScopeUsesRequestContext(Tracing tracing) { final PingPongExtra extra = new PingPongExtra(); // trace contexts are not recorded until Tracer.toSpan, so this won't end up as junk data final TraceContext dummyContext = TraceContext.newBuilder().traceId(1).spanId(1) .extra(Collections.singletonList(extra)).build(); final boolean scopeUsesRequestContext; try (Scope scope = tracing.currentTraceContext().newScope(dummyContext)) { scopeUsesRequestContext = extra.isPong(); } if (!scopeUsesRequestContext) { throw new IllegalStateException( "Tracing.currentTraceContext is not a " + RequestContextCurrentTraceContext.class .getSimpleName() + " scope. " + "Please call Tracing.Builder.currentTraceContext(" + RequestContextCurrentTraceContext.class .getSimpleName() + ".INSTANCE)."); } }
@Test public void newScope_notOnEventLoop() { final TraceContext traceContext2 = TraceContext.newBuilder().traceId(1).spanId(2).build(); try (SafeCloseable requestContextScope = mockRequestContext.push()) { try (Scope traceContextScope = currentTraceContext.newScope(traceContext)) { assertThat(traceContextScope).hasToString("InitialRequestScope"); assertThat(currentTraceContext.get()).isEqualTo(traceContext); when(eventLoop.inEventLoop()).thenReturn(false); try (Scope traceContextScope2 = currentTraceContext.newScope(traceContext2)) { assertThat(traceContextScope2).hasToString("ThreadLocalScope"); assertThat(currentTraceContext.get()).isEqualTo(traceContext2); } when(eventLoop.inEventLoop()).thenReturn(true); assertThat(currentTraceContext.get()).isEqualTo(traceContext); } // the first scope is attached to the request context and cleared when that's destroyed assertThat(currentTraceContext.get()).isEqualTo(traceContext); } }
@Test public void restoresSpanAfterRunnable() throws Exception { TraceContext context0 = TraceContext.newBuilder().traceId(3L).spanId(3L).build(); try (Scope scope0 = currentTraceContext.newScope(context0)) { attachesSpanInRunnable(); assertThat(currentTraceContext.get()) .isEqualTo(context0); verifyImplicitContext(context0); } }
@Test public void verifyRoundTrip_128BitTrace() throws Exception { String high64Bits = "463ac35c9f6413ad"; String low64Bits = "48485a3953bb6124"; inject(map, high64Bits + low64Bits, null, low64Bits, true, null); verifyRoundTrip(TraceContextOrSamplingFlags.create(rootSpan.toBuilder() .traceIdHigh(HexCodec.lowerHexToUnsignedLong(high64Bits)) .traceId(HexCodec.lowerHexToUnsignedLong(low64Bits)) .spanId(HexCodec.lowerHexToUnsignedLong(low64Bits)).build())); }
public static TraceContext toTraceContext(SpanId spanId) { // visible for testing if (spanId == null) throw new NullPointerException("spanId == null"); return TraceContext.newBuilder() .traceIdHigh(spanId.traceIdHigh) .traceId(spanId.traceId) .parentId(spanId.nullableParentId()) .spanId(spanId.spanId) .debug(spanId.debug()) .sampled(spanId.sampled()).build(); }
void noticesDifferentSpanId(Scope scope) { TraceContext differentSpanId = context.toBuilder().spanId(context.spanId() + 1L).build(); try (Scope scope2 = currentTraceContext.maybeScope(differentSpanId)) { assertThat(scope2).isNotEqualTo(Scope.NOOP); assertThat(currentTraceContext.get()) .isEqualTo(differentSpanId); verifyImplicitContext(differentSpanId); } finally { scope.close(); } }
@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"); } }
if (sampled != null) builder.sampled(sampled.booleanValue()); if (tags != null) builder.extra(Collections.singletonList(tags)); return builder.build();
@Override public TraceContextOrSamplingFlags extract(C carrier) { if (carrier == null) throw new NullPointerException("carrier == null"); // try to extract single-header format TraceContextOrSamplingFlags extracted = singleExtractor.extract(carrier); if (!extracted.equals(TraceContextOrSamplingFlags.EMPTY)) return extracted; // Start by looking at the sampled state as this is used regardless // Official sampled value is 1, though some old instrumentation send true String sampled = getter.get(carrier, propagation.sampledKey); Boolean sampledV = sampled != null ? sampled.equals("1") || sampled.equalsIgnoreCase("true") : null; boolean debug = "1".equals(getter.get(carrier, propagation.debugKey)); String traceIdString = getter.get(carrier, propagation.traceIdKey); // It is ok to go without a trace ID, if sampling or debug is set if (traceIdString == null) return TraceContextOrSamplingFlags.create(sampledV, debug); // Try to parse the trace IDs into the context TraceContext.Builder result = TraceContext.newBuilder(); if (result.parseTraceId(traceIdString, propagation.traceIdKey) && result.parseSpanId(getter, carrier, propagation.spanIdKey) && result.parseParentId(getter, carrier, propagation.parentSpanIdKey)) { if (sampledV != null) result.sampled(sampledV.booleanValue()); if (debug) result.debug(true); return TraceContextOrSamplingFlags.create(result.build()); } return TraceContextOrSamplingFlags.EMPTY; // trace context is malformed so return empty } }
@Test public void newScope_closeDoesntClearFirstScope() { final TraceContext traceContext2 = TraceContext.newBuilder().traceId(1).spanId(2).build(); try (SafeCloseable requestContextScope = mockRequestContext.push()) { try (Scope traceContextScope = currentTraceContext.newScope(traceContext)) { assertThat(traceContextScope).hasToString("InitialRequestScope"); assertThat(currentTraceContext.get()).isEqualTo(traceContext); try (Scope traceContextScope2 = currentTraceContext.newScope(traceContext2)) { assertThat(traceContextScope2).hasToString("RequestContextTraceContextScope"); assertThat(currentTraceContext.get()).isEqualTo(traceContext2); } assertThat(currentTraceContext.get()).isEqualTo(traceContext); } // the first scope is attached to the request context and cleared when that's destroyed assertThat(currentTraceContext.get()).isEqualTo(traceContext); } }
@Test public void restoresSpanAfterRunnable() throws Exception { TraceContext context0 = TraceContext.newBuilder().traceId(3L).spanId(3L).build(); try (Scope scope0 = currentTraceContext.newScope(context0)) { attachesSpanInRunnable(); assertThat(currentTraceContext.get()) .isEqualTo(context0); verifyImplicitContext(context0); } }
@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"); } }
/** * When the caller propagates IDs, but not a sampling decision, the current process should * decide. */ @Test public void verifyRoundTrip_externallyProvidedIds() { inject(map, "0000000000000001", null, "0000000000000001", null, null); verifyRoundTrip(TraceContextOrSamplingFlags.create(rootSpan.toBuilder().sampled(null).build())); }
@Test public void verifyRoundTrip_128BitTrace() throws Exception { String high64Bits = "463ac35c9f6413ad"; String low64Bits = "48485a3953bb6124"; inject(map, high64Bits + low64Bits, null, low64Bits, true, null); verifyRoundTrip(TraceContextOrSamplingFlags.create(rootSpan.toBuilder() .traceIdHigh(HexCodec.lowerHexToUnsignedLong(high64Bits)) .traceId(HexCodec.lowerHexToUnsignedLong(low64Bits)) .spanId(HexCodec.lowerHexToUnsignedLong(low64Bits)).build())); }
@Override public void accept(CurrentTraceContext current) { current.newScope(TraceContext.newBuilder().traceId(1L).spanId(2L).build()); } }
@Override public void accept(CurrentTraceContext current) { try (Scope ws = current.newScope(TraceContext.newBuilder().traceId(1L).spanId(2L).build())) { } } }
@Test public void newScope_respondsToPing() { final PingPongExtra extra = new PingPongExtra(); final TraceContext extraContext = TraceContext.newBuilder().traceId(1).spanId(1) .extra(Collections.singletonList(extra)).build(); try (Scope traceContextScope = currentTraceContext.newScope(extraContext)) { assertThat(traceContextScope).hasToString("NoopScope"); assertThat(extra.isPong()).isTrue(); } }
@Test public void verifyRoundTrip_notSampled() throws Exception { inject(map, "0000000000000001", "0000000000000001", "0000000000000002", false, null); verifyRoundTrip(TraceContextOrSamplingFlags.create( childSpan.toBuilder().sampled(false).build() )); }
@Test public void shouldSetPongIfOnlyExtra() { final PingPongExtra extra = new PingPongExtra(); final TraceContext context = TraceContext.newBuilder().traceId(1).spanId(1) .extra(Collections.singletonList(extra)).build(); PingPongExtra.maybeSetPong(context); assertThat(extra.isPong()).isTrue(); } }