final Span wingtipsSpan = Span.newBuilder("foo", SpanPurpose.CLIENT) .withTraceId(badTraceId) .withSpanId(badSpanId) .withParentSpanId(badParentSpanId) .withSpanStartTimeEpochMicros(Math.abs(random.nextLong()))
@Test public void convertSpanToKeyValueFormat_and_fromKeyValueString_should_escape_and_unescape_expected_non_tag_or_annotation_values() { // The TAGS_AND_ANNOTATIONS_WITH_SPECIAL_CHARS case already verified tags and annotations. Now we need to // verify that non-tag values are escaped. Also note that other tests have verified that escapeJson() // and unescapeJson() work properly. // given String complexSpanName = "span-name-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; String complexTraceId = "trace-id-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; String complexParentId = "parent-id-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; String complexSpanId = "span-id-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; String complexUserId = "user-id-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; Span span = Span.newBuilder(complexSpanName, SpanPurpose.CLIENT) .withTraceId(complexTraceId) .withParentSpanId(complexParentId) .withSpanId(complexSpanId) .withUserId(complexUserId) .build(); // when String keyValueStr = SpanParser.convertSpanToKeyValueFormat(span); // then assertThat(keyValueStr).contains("traceId=\"trace-id-" + ESCAPED_JSON_CHARS + "\""); assertThat(keyValueStr).contains("parentSpanId=\"parent-id-" + ESCAPED_JSON_CHARS + "\""); assertThat(keyValueStr).contains("spanId=\"span-id-" + ESCAPED_JSON_CHARS + "\""); assertThat(keyValueStr).contains("userId=\"user-id-" + ESCAPED_JSON_CHARS + "\""); assertThat(keyValueStr).contains("spanName=\"span-name-" + ESCAPED_JSON_CHARS + "\""); // and when Span deserialized = SpanParser.fromKeyValueString(keyValueStr); // then verifySpanDeepEquals(deserialized, span, true); }
@UseDataProvider("idSanitizationScenarios") @Test public void convertWingtipsSpanToZipkinSpan_sanitizes_spanId_as_expected_when_sanitization_is_enabled( IdSanitizationScenario scenario ) { // given impl = new WingtipsToZipkinSpanConverterDefaultImpl(true); final Endpoint zipkinEndpoint = Endpoint.newBuilder().serviceName(UUID.randomUUID().toString()).build(); final Span wingtipsSpan = Span.newBuilder("foo", SpanPurpose.CLIENT) .withSpanId(scenario.originalId) .withSpanStartTimeEpochMicros(Math.abs(random.nextLong())) .withDurationNanos(Math.abs(random.nextLong())) .build(); // when zipkin2.Span zipkinSpan = impl.convertWingtipsSpanToZipkinSpan(wingtipsSpan, zipkinEndpoint); // then assertThat(zipkinSpan.id()).isEqualTo(scenario.expectedSanitizedResultForSpanIdOrParentSpanId); assertThat(zipkinSpan.tags().get("invalid.span_id")).isEqualTo(scenario.originalId); }
.newBuilder("override_me", SpanPurpose.UNKNOWN) .withTraceId(traceId) .withSpanId(spanId) .withParentSpanId(parentSpanId) .withSpanName(spanName)
.withTraceId(traceId) .withParentSpanId(getSpanIdFromRequest(request, TraceHeaders.PARENT_SPAN_ID, false)) .withSpanId(getSpanIdFromRequest(request, TraceHeaders.SPAN_ID, true)) .withSampleable(getSpanSampleableFlag(request)) .withUserId(getUserIdFromRequestWithHeaders(request, userIdHeaderKeys))
@Test public void convertSpanToJSON_and_fromJSON_should_escape_and_unescape_expected_non_tag_or_annotation_values() { // The TAGS_AND_ANNOTATIONS_WITH_SPECIAL_CHARS case already verified tags and annotations. Now we need to // verify that non-tag values are escaped. Also note that other tests have verified that escapeJson() // and unescapeJson() work properly. // given String complexSpanName = "span-name-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; String complexTraceId = "trace-id-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; String complexParentId = "parent-id-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; String complexSpanId = "span-id-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; String complexUserId = "user-id-" + ALL_JSON_CHARS_THAT_NEED_ESCAPING; Span span = Span.newBuilder(complexSpanName, SpanPurpose.CLIENT) .withTraceId(complexTraceId) .withParentSpanId(complexParentId) .withSpanId(complexSpanId) .withUserId(complexUserId) .build(); // when String json = SpanParser.convertSpanToJSON(span); // then assertThat(json).contains("\"traceId\":\"trace-id-" + ESCAPED_JSON_CHARS + "\""); assertThat(json).contains("\"parentSpanId\":\"parent-id-" + ESCAPED_JSON_CHARS + "\""); assertThat(json).contains("\"spanId\":\"span-id-" + ESCAPED_JSON_CHARS + "\""); assertThat(json).contains("\"userId\":\"user-id-" + ESCAPED_JSON_CHARS + "\""); assertThat(json).contains("\"spanName\":\"span-name-" + ESCAPED_JSON_CHARS + "\""); // and when Span deserialized = SpanParser.fromJSON(json); // then verifySpanDeepEquals(deserialized, span, true); }
@UseDataProvider("idSanitizationScenarios") @Test public void convertWingtipsSpanToZipkinSpan_does_not_sanitize_ids_if_enableIdSanitization_is_false( IdSanitizationScenario scenario ) { // given impl = new WingtipsToZipkinSpanConverterDefaultImpl(false); final Endpoint zipkinEndpoint = Endpoint.newBuilder().serviceName(UUID.randomUUID().toString()).build(); final Span wingtipsSpan = Span.newBuilder("foo", SpanPurpose.CLIENT) .withTraceId(scenario.originalId) .withSpanId(scenario.originalId) .withSpanStartTimeEpochMicros(Math.abs(random.nextLong())) .withDurationNanos(Math.abs(random.nextLong())) .build(); String expectedExceptionMessageSuffix = (scenario.originalId.length() > 16) ? "id.length > 16" : "should be lower-hex encoded with no prefix"; // when Throwable ex = catchThrowable(() -> impl.convertWingtipsSpanToZipkinSpan(wingtipsSpan, zipkinEndpoint)); // then assertThat(ex) .isInstanceOf(IllegalArgumentException.class) .hasMessageEndingWith(expectedExceptionMessageSuffix); }
/** * @param spanName The {@link Span#getSpanName()} to use for the new child sub-span. * @param spanPurpose The {@link SpanPurpose} for the new child span. See the javadocs for {@link SpanPurpose} for full details on what each enum option * means. If you pass in null for this then {@link SpanPurpose#UNKNOWN} will be used. * @return A new uncompleted span representing a child of this instance. The returned instance's {@link #getParentSpanId()} will be this instance's * {@link #getSpanId()}, its {@link #getSpanName()} will be the given value, its {@link #getSpanId()} will be randomly generated, and its * {@link #getSpanStartTimeEpochMicros()} and {@link #getSpanStartTimeNanos()} values will be set to the appropriate values based on when this * method is called. It will share this instance's {@link #getTraceId()}, {@link #isSampleable()}, and {@link #getUserId()} values. */ public Span generateChildSpan(String spanName, SpanPurpose spanPurpose) { return Span.newBuilder(spanName, spanPurpose) .withTraceId(this.getTraceId()) .withSampleable(this.isSampleable()) .withUserId(this.getUserId()) .withParentSpanId(this.getSpanId()) .withSpanId(TraceAndSpanIdGenerator.generateId()) .withSpanStartTimeEpochMicros(TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis())) .withSpanStartTimeNanos(System.nanoTime()) .withDurationNanos(null) .build(); }