Skip to content

Commit

Permalink
Translate Spring 6 Zipkin spans to Stackdriver convention
Browse files Browse the repository at this point in the history
Applies the logic necessary for translating Spring 6 made Zipkin spans to Stackdriver spans with the conventional Stackdriver attribute naming.
  • Loading branch information
shakuzen committed Nov 29, 2024
1 parent 56a55ce commit 8ee1005
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.google.devtools.cloudtrace.v2.Span.TimeEvents;
import com.google.protobuf.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -16,6 +17,7 @@
import zipkin2.Span;

import static java.util.logging.Level.FINE;
import static zipkin2.translation.stackdriver.AttributesExtractor.toAttributeValue;
import static zipkin2.translation.stackdriver.SpanUtil.toTruncatableString;

/** SpanTranslator converts a Zipkin Span to a Stackdriver Trace Span. */
Expand All @@ -35,6 +37,15 @@ public final class SpanTranslator {
ATTRIBUTES_EXTRACTOR = new AttributesExtractor(renamedLabels);
}

private static final Map<String, String> SPRING6_RENAMED_HTTP_LABELS;

static {
Map<String, String> map = new LinkedHashMap<>();
map.put("status", "/http/status_code");
map.put("method", "/http/method");
SPRING6_RENAMED_HTTP_LABELS = Collections.unmodifiableMap(map);
}

/**
* Convert a Collection of Zipkin Spans into a Collection of Stackdriver Trace Spans.
*
Expand Down Expand Up @@ -104,6 +115,16 @@ public static com.google.devtools.cloudtrace.v2.Span.Builder translate(
}
spanBuilder.setAttributes(ATTRIBUTES_EXTRACTOR.extract(zipkinSpan));

// Spring 6 HTTP spans need mapping to Stackdriver conventional attribute names
if (zipkinSpan.name() != null && zipkinSpan.name().contains("http")) {
zipkinSpan.tags().forEach((key, value) -> {
if (SPRING6_RENAMED_HTTP_LABELS.containsKey(key)) {
spanBuilder.getAttributesBuilder()
.putAttributeMap(SPRING6_RENAMED_HTTP_LABELS.get(key), toAttributeValue(value));
}
});
}

if (!zipkinSpan.annotations().isEmpty()) {
TimeEvents.Builder events = TimeEvents.newBuilder();
for (Annotation annotation : zipkinSpan.annotations()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,59 @@ public class SpanTranslatorTest {
assertThat(stackdriverSpans.get(1).getDisplayName().getValue()).isEqualTo("unknown");
assertThat(stackdriverSpans.get(2).getDisplayName().getValue()).isEqualTo("somename");
}

@Test void translate_spring6ServerSpan() {
Span zipkinSpan =
Span.newBuilder()
.traceId("7180c278b62e8f6a216a2aea45d08fc9")
.id("5b4185666d50f68b")
.name("http get /test")
.kind(Span.Kind.SERVER)
.localEndpoint(Endpoint.newBuilder().serviceName("backend").build())
.timestamp(1_000_000L) // 1 second after epoch
.duration(123_456L)
.addAnnotation(1_123_000L, "foo")
.putTag("exception", "none")
.putTag("http.url", "/test")
.putTag("method", "GET")
.putTag("outcome", "SUCCESS")
.putTag("status", "200")
.putTag("uri", "/test")
.build();

com.google.devtools.cloudtrace.v2.Span
translated = SpanTranslator.translate(
com.google.devtools.cloudtrace.v2.Span.newBuilder(), zipkinSpan).build();

assertThat(translated)
.isEqualTo(
com.google.devtools.cloudtrace.v2.Span.newBuilder()
.setSpanId(zipkinSpan.id())
.setDisplayName(toTruncatableString("http get /test"))
.setStartTime(Timestamp.newBuilder().setSeconds(1).build())
.setEndTime(Timestamp.newBuilder().setSeconds(1).setNanos(123_456_000).build())
.setAttributes(com.google.devtools.cloudtrace.v2.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"))
.build())
.setTimeEvents(com.google.devtools.cloudtrace.v2.Span.TimeEvents.newBuilder()
.addTimeEvent(com.google.devtools.cloudtrace.v2.Span.TimeEvent.newBuilder()
.setTime(createTimestamp(1_123_000L))
.setAnnotation(
com.google.devtools.cloudtrace.v2.Span.TimeEvent.Annotation.newBuilder()
.setDescription(toTruncatableString("foo"))
.build())
.build())
.build())
.build());
}
}

0 comments on commit 8ee1005

Please sign in to comment.