diff --git a/exporters/trace/jaeger/src/main/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandler.java b/exporters/trace/jaeger/src/main/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandler.java index b16a915945..3ef7ee7d05 100644 --- a/exporters/trace/jaeger/src/main/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandler.java +++ b/exporters/trace/jaeger/src/main/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandler.java @@ -21,6 +21,7 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.common.primitives.Ints; import com.google.common.primitives.Longs; @@ -44,6 +45,7 @@ import io.opencensus.trace.MessageEvent.Type; import io.opencensus.trace.SpanContext; import io.opencensus.trace.SpanId; +import io.opencensus.trace.Status; import io.opencensus.trace.TraceId; import io.opencensus.trace.TraceOptions; import io.opencensus.trace.export.SpanData; @@ -57,7 +59,7 @@ @NotThreadSafe final class JaegerExporterHandler extends TimeLimitedHandler { private static final String EXPORT_SPAN_NAME = "ExportJaegerTraces"; - private static final String SPAN_KIND = "span.kind"; + @VisibleForTesting static final String SPAN_KIND = "span.kind"; private static final Tag SERVER_KIND_TAG = new Tag(SPAN_KIND, TagType.STRING).setVStr("server"); private static final Tag CLIENT_KIND_TAG = new Tag(SPAN_KIND, TagType.STRING).setVStr("client"); private static final String DESCRIPTION = "message"; @@ -68,6 +70,8 @@ final class JaegerExporterHandler extends TimeLimitedHandler { private static final String MESSAGE_EVENT_ID = "id"; private static final String MESSAGE_EVENT_COMPRESSED_SIZE = "compressed_size"; private static final String MESSAGE_EVENT_UNCOMPRESSED_SIZE = "uncompressed_size"; + @VisibleForTesting static final String STATUS_CODE = "status.code"; + @VisibleForTesting static final String STATUS_MESSAGE = "status.message"; private static final Function stringAttributeConverter = new Function() { @@ -161,6 +165,11 @@ private Span spanDataToJaegerThriftSpan(final SpanData spanData) { final SpanContext context = spanData.getContext(); copyToBuffer(context.getTraceId()); + List tags = + attributesToTags( + spanData.getAttributes().getAttributeMap(), spanKindToTag(spanData.getKind())); + addStatusTags(tags, spanData.getStatus()); + return new io.jaegertracing.thriftjava.Span( traceIdLow(), traceIdHigh(), @@ -171,9 +180,7 @@ private Span spanDataToJaegerThriftSpan(final SpanData spanData) { startTimeInMicros, endTimeInMicros - startTimeInMicros) .setReferences(linksToReferences(spanData.getLinks().getLinks())) - .setTags( - attributesToTags( - spanData.getAttributes().getAttributeMap(), spanKindToTag(spanData.getKind()))) + .setTags(tags) .setLogs( timedEventsToLogs( spanData.getAnnotations().getEvents(), spanData.getMessageEvents().getEvents())); @@ -335,4 +342,15 @@ private static Tag spanKindToTag(@Nullable final io.opencensus.trace.Span.Kind k } return null; } + + private static void addStatusTags(List tags, @Nullable Status status) { + if (status == null) { + return; + } + Tag statusTag = new Tag(STATUS_CODE, TagType.LONG).setVLong(status.getCanonicalCode().value()); + tags.add(statusTag); + if (status.getDescription() != null) { + tags.add(new Tag(STATUS_MESSAGE, TagType.STRING).setVStr(status.getDescription())); + } + } } diff --git a/exporters/trace/jaeger/src/test/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandlerIntegrationTest.java b/exporters/trace/jaeger/src/test/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandlerIntegrationTest.java index 0a8317f211..151d155b28 100644 --- a/exporters/trace/jaeger/src/test/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandlerIntegrationTest.java +++ b/exporters/trace/jaeger/src/test/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandlerIntegrationTest.java @@ -173,11 +173,15 @@ public void exportToJaeger() throws IOException, InterruptedException { assertThat(span.get("duration").getAsLong()).isAtMost(durationInMicros); JsonArray tags = span.get("tags").getAsJsonArray(); - assertThat(tags.size()).isEqualTo(1); + assertThat(tags.size()).isEqualTo(2); JsonObject tag = tags.get(0).getAsJsonObject(); assertThat(tag.get("key").getAsString()).isEqualTo("foo"); assertThat(tag.get("type").getAsString()).isEqualTo("string"); assertThat(tag.get("value").getAsString()).isEqualTo("bar"); + JsonObject statusTag = tags.get(1).getAsJsonObject(); + assertThat(statusTag.get("key").getAsString()).isEqualTo(JaegerExporterHandler.STATUS_CODE); + assertThat(statusTag.get("type").getAsString()).isEqualTo("int64"); + assertThat(statusTag.get("value").getAsLong()).isEqualTo(0); JsonArray logs = span.get("logs").getAsJsonArray(); assertThat(logs.size()).isEqualTo(2); diff --git a/exporters/trace/jaeger/src/test/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandlerTest.java b/exporters/trace/jaeger/src/test/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandlerTest.java index ceebce36d0..c4f71fd016 100644 --- a/exporters/trace/jaeger/src/test/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandlerTest.java +++ b/exporters/trace/jaeger/src/test/java/io/opencensus/exporter/trace/jaeger/JaegerExporterHandlerTest.java @@ -48,6 +48,8 @@ import io.opencensus.trace.TraceOptions; import io.opencensus.trace.Tracestate; import io.opencensus.trace.export.SpanData; +import io.opencensus.trace.export.SpanData.TimedEvent; +import java.util.Collections; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -103,15 +105,15 @@ public void exportShouldConvertFromSpanDataToJaegerThriftSpan() throws SenderExc assertThat(span.startTime).isEqualTo(MILLISECONDS.toMicros(startTime)); assertThat(span.duration).isEqualTo(MILLISECONDS.toMicros(endTime - startTime)); - assertThat(span.tags.size()).isEqualTo(4); + assertThat(span.tags.size()).isEqualTo(5); assertThat(span.tags) .containsExactly( new Tag("BOOL", TagType.BOOL).setVBool(false), new Tag("LONG", TagType.LONG).setVLong(Long.MAX_VALUE), - new Tag("span.kind", TagType.STRING).setVStr("server"), + new Tag(JaegerExporterHandler.SPAN_KIND, TagType.STRING).setVStr("server"), new Tag("STRING", TagType.STRING) - .setVStr( - "Judge of a man by his questions rather than by his answers. -- Voltaire")); + .setVStr("Judge of a man by his questions rather than by his answers. -- Voltaire"), + new Tag(JaegerExporterHandler.STATUS_CODE, TagType.LONG).setVLong(0)); assertThat(span.logs.size()).isEqualTo(2); Log log = span.logs.get(0); @@ -142,6 +144,43 @@ public void exportShouldConvertFromSpanDataToJaegerThriftSpan() throws SenderExc assertThat(reference.refType).isEqualTo(SpanRefType.CHILD_OF); } + @Test + public void convertErrorSpanDataToJaegerThriftSpan() throws SenderException { + long startTime = 1519629870001L; + long endTime = 1519630148002L; + String statusMessage = "timeout"; + SpanData spanData = + SpanData.create( + sampleSpanContext(), + SpanId.fromBytes(new byte[] {(byte) 0x7F, FF, FF, FF, FF, FF, FF, FF}), + true, + "test", + Kind.SERVER, + Timestamp.fromMillis(startTime), + SpanData.Attributes.create(Collections.emptyMap(), 0), + SpanData.TimedEvents.create(Collections.>emptyList(), 0), + SpanData.TimedEvents.create(Collections.>emptyList(), 0), + SpanData.Links.create(Collections.emptyList(), 0), + 0, + Status.DEADLINE_EXCEEDED.withDescription(statusMessage), + Timestamp.fromMillis(endTime)); + + handler.export(singletonList(spanData)); + + verify(mockSender).send(eq(process), captor.capture()); + List spans = captor.getValue(); + + assertThat(spans.size()).isEqualTo(1); + Span span = spans.get(0); + + assertThat(span.tags.size()).isEqualTo(3); + assertThat(span.tags) + .containsExactly( + new Tag(JaegerExporterHandler.SPAN_KIND, TagType.STRING).setVStr("server"), + new Tag(JaegerExporterHandler.STATUS_CODE, TagType.LONG).setVLong(4), + new Tag(JaegerExporterHandler.STATUS_MESSAGE, TagType.STRING).setVStr(statusMessage)); + } + private static SpanContext sampleSpanContext() { return SpanContext.create( TraceId.fromBytes(new byte[] {FF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}),