diff --git a/encoder-stackdriver-brave/src/main/java/zipkin2/reporter/stackdriver/brave/SpanTranslator.java b/encoder-stackdriver-brave/src/main/java/zipkin2/reporter/stackdriver/brave/SpanTranslator.java index 50b6488..28f5c2c 100644 --- a/encoder-stackdriver-brave/src/main/java/zipkin2/reporter/stackdriver/brave/SpanTranslator.java +++ b/encoder-stackdriver-brave/src/main/java/zipkin2/reporter/stackdriver/brave/SpanTranslator.java @@ -10,11 +10,14 @@ import com.google.devtools.cloudtrace.v2.Span.TimeEvent; import com.google.devtools.cloudtrace.v2.Span.TimeEvents; import com.google.protobuf.Timestamp; + +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.logging.Logger; import static java.util.logging.Level.FINE; +import static zipkin2.reporter.stackdriver.brave.AttributesExtractor.toAttributeValue; import static zipkin2.reporter.stackdriver.brave.SpanUtil.toTruncatableString; /** SpanTranslator converts a Zipkin Span to a Stackdriver Trace Span. */ @@ -33,6 +36,15 @@ final class SpanTranslator { RENAMED_LABELS.put("http.url", "/http/url"); } + private static final Map SPRING6_RENAMED_HTTP_LABELS; + + static { + Map map = new LinkedHashMap<>(); + map.put("status", "/http/status_code"); + map.put("method", "/http/method"); + SPRING6_RENAMED_HTTP_LABELS = Collections.unmodifiableMap(map); + } + private final AttributesExtractor attributesExtractor; SpanTranslator(Tag errorTag) { @@ -79,6 +91,16 @@ Span.Builder translate(Span.Builder spanBuilder, MutableSpan braveSpan) { } spanBuilder.setAttributes(attributesExtractor.extract(braveSpan)); + // Spring 6 HTTP spans need mapping to Stackdriver conventional attribute names + if (braveSpan.name() != null && braveSpan.name().contains("http")) { + braveSpan.tags().forEach((key, value) -> { + if (SPRING6_RENAMED_HTTP_LABELS.containsKey(key)) { + spanBuilder.getAttributesBuilder() + .putAttributeMap(SPRING6_RENAMED_HTTP_LABELS.get(key), toAttributeValue(value)); + } + }); + } + if (braveSpan.annotationCount() > 0) { TimeEvents.Builder events = TimeEvents.newBuilder(); braveSpan.forEachAnnotation(SpanTranslator::addAnnotation, events); diff --git a/encoder-stackdriver-brave/src/test/java/zipkin2/reporter/stackdriver/brave/SpanTranslatorTest.java b/encoder-stackdriver-brave/src/test/java/zipkin2/reporter/stackdriver/brave/SpanTranslatorTest.java index 9904ec5..4ef3101 100644 --- a/encoder-stackdriver-brave/src/test/java/zipkin2/reporter/stackdriver/brave/SpanTranslatorTest.java +++ b/encoder-stackdriver-brave/src/test/java/zipkin2/reporter/stackdriver/brave/SpanTranslatorTest.java @@ -15,6 +15,7 @@ import static zipkin2.reporter.stackdriver.brave.AttributesExtractor.toAttributeValue; import static zipkin2.reporter.stackdriver.brave.SpanUtil.toTruncatableString; import static zipkin2.reporter.stackdriver.brave.TestObjects.clientSpan; +import static zipkin2.reporter.stackdriver.brave.TestObjects.spring6ServerSpan; class SpanTranslatorTest { SpanTranslator spanTranslator = new SpanTranslator(Tags.ERROR); @@ -73,4 +74,48 @@ class SpanTranslatorTest { assertThat(translated.getDisplayName().getValue()).isEqualTo("unknown"); } + + @Test void translate_spring6ServerSpan() { + MutableSpan braveSpan = spring6ServerSpan(); + Span translated = spanTranslator.translate(Span.newBuilder(), braveSpan).build(); + + assertThat(translated) + .isEqualTo( + Span.newBuilder() + .setSpanId(braveSpan.id()) + .setDisplayName(toTruncatableString("http get /test")) + .setStartTime(Timestamp.newBuilder().setSeconds(1472470996).setNanos(199_000_000).build()) + .setEndTime(Timestamp.newBuilder().setSeconds(1472470996).setNanos(406_000_000).build()) + .setAttributes(Span.Attributes.newBuilder() + .putAttributeMap("/agent", toAttributeValue("zipkin-java")) + .putAttributeMap("exception", toAttributeValue("none")) + .putAttributeMap("/http/url", toAttributeValue("/test")) + .putAttributeMap("/http/method", toAttributeValue("GET")) + .putAttributeMap("outcome", toAttributeValue("SUCCESS")) + .putAttributeMap("/http/status_code", toAttributeValue("200")) + .putAttributeMap("uri", toAttributeValue("/test")) + .putAttributeMap("method", toAttributeValue("GET")) + .putAttributeMap("status", toAttributeValue("200")) + .putAttributeMap("/kind", toAttributeValue("server")) + .putAttributeMap("/component", toAttributeValue("backend")) + .putAttributeMap("endpoint.ipv4", toAttributeValue("127.0.0.1")) + .build()) + .setTimeEvents(Span.TimeEvents.newBuilder() + .addTimeEvent(Span.TimeEvent.newBuilder() + .setTime(Timestamp.newBuilder().setSeconds(1472470996).setNanos(238_000_000).build()) + .setAnnotation( + Span.TimeEvent.Annotation.newBuilder() + .setDescription(toTruncatableString("foo")) + .build()) + .build()) + .addTimeEvent(Span.TimeEvent.newBuilder() + .setTime(Timestamp.newBuilder().setSeconds(1472470996).setNanos(403_000_000).build()) + .setAnnotation( + Span.TimeEvent.Annotation.newBuilder() + .setDescription(toTruncatableString("bar")) + .build()) + .build()) + .build()) + .build()); + } } diff --git a/encoder-stackdriver-brave/src/test/java/zipkin2/reporter/stackdriver/brave/TestObjects.java b/encoder-stackdriver-brave/src/test/java/zipkin2/reporter/stackdriver/brave/TestObjects.java index 87d8fda..77a6669 100644 --- a/encoder-stackdriver-brave/src/test/java/zipkin2/reporter/stackdriver/brave/TestObjects.java +++ b/encoder-stackdriver-brave/src/test/java/zipkin2/reporter/stackdriver/brave/TestObjects.java @@ -26,4 +26,25 @@ static MutableSpan clientSpan() { braveSpan.tag("http.path", "/api"); return braveSpan; } + + static MutableSpan spring6ServerSpan() { + MutableSpan braveSpan = new MutableSpan(); + braveSpan.traceId("673adb3c54aa03af9e941a86a679a9d5"); + braveSpan.id("9e941a86a679a9d5"); + braveSpan.name("http get /test"); + braveSpan.kind(brave.Span.Kind.SERVER); + braveSpan.localServiceName("backend"); + braveSpan.localIp("127.0.0.1"); + braveSpan.startTimestamp(1472470996199000L); + braveSpan.finishTimestamp(1472470996199000L + 207000L); + braveSpan.annotate(1472470996238000L, "foo"); + braveSpan.annotate(1472470996403000L, "bar"); + braveSpan.tag("exception", "none"); + braveSpan.tag("http.url", "/test"); + braveSpan.tag("method", "GET"); + braveSpan.tag("outcome", "SUCCESS"); + braveSpan.tag("status", "200"); + braveSpan.tag("uri", "/test"); + return braveSpan; + } }