diff --git a/jaeger-zipkin/src/main/java/com/uber/jaeger/senders/zipkin/ThriftSpanConverter.java b/jaeger-zipkin/src/main/java/com/uber/jaeger/senders/zipkin/ThriftSpanConverter.java index 56756cadb..3aa4d6744 100644 --- a/jaeger-zipkin/src/main/java/com/uber/jaeger/senders/zipkin/ThriftSpanConverter.java +++ b/jaeger-zipkin/src/main/java/com/uber/jaeger/senders/zipkin/ThriftSpanConverter.java @@ -22,6 +22,7 @@ package com.uber.jaeger.senders.zipkin; +import com.google.gson.Gson; import com.twitter.zipkin.thriftjava.Annotation; import com.twitter.zipkin.thriftjava.AnnotationType; import com.twitter.zipkin.thriftjava.BinaryAnnotation; @@ -42,6 +43,7 @@ public class ThriftSpanConverter { private static final Charset UTF_8 = Charset.forName("UTF-8"); + private static final Gson gson = new Gson(); public static com.twitter.zipkin.thriftjava.Span convertSpan(Span span) { Tracer tracer = span.getTracer(); @@ -78,7 +80,13 @@ private static List buildAnnotations(Span span, Endpoint host) { List logs = span.getLogs(); if (logs != null) { for (LogData logData : logs) { - annotations.add(new Annotation(logData.getTime(), logData.getMessage())); + String logMessage = logData.getMessage(); + Map logFields = logData.getFields(); + if (logMessage != null) { + annotations.add(new Annotation(logData.getTime(), logMessage)); + } else if (logFields != null) { + annotations.add(new Annotation(logData.getTime(), gson.toJson(logFields))); + } } } diff --git a/jaeger-zipkin/src/test/java/com/uber/jaeger/senders/zipkin/ThriftSpanConverterTest.java b/jaeger-zipkin/src/test/java/com/uber/jaeger/senders/zipkin/ThriftSpanConverterTest.java index 37aa4b84f..d303e0334 100644 --- a/jaeger-zipkin/src/test/java/com/uber/jaeger/senders/zipkin/ThriftSpanConverterTest.java +++ b/jaeger-zipkin/src/test/java/com/uber/jaeger/senders/zipkin/ThriftSpanConverterTest.java @@ -44,9 +44,11 @@ import io.opentracing.propagation.TextMapInjectAdapter; import io.opentracing.tag.Tags; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.TreeMap; import org.junit.Before; import org.junit.Test; @@ -277,4 +279,32 @@ public void testRpcChildSpanHasTheSameId() { assertEquals("client and server must have the same span ID", client.context().getSpanId(), server.context().getSpanId()); } + + @Test + public void testSpanLogsCreateAnnotations() { + Span span = (com.uber.jaeger.Span) tracer.buildSpan("span-with-logs").startManual(); + + span.log("event"); + + // use sorted map for consistent ordering in test + Map fields = new TreeMap(); + fields.put("event", "structured data"); + fields.put("string", "something"); + fields.put("number", 42); + fields.put("boolean", true); + span.log(fields); + + com.twitter.zipkin.thriftjava.Span zipkinSpan = ThriftSpanConverter.convertSpan(span); + + List annotationValues = new ArrayList(); + for (Annotation annotation : zipkinSpan.getAnnotations()) { + annotationValues.add(annotation.getValue()); + } + + List expectedValues = new ArrayList(); + expectedValues.add("event"); + expectedValues.add("{\"boolean\":true,\"event\":\"structured data\",\"number\":42,\"string\":\"something\"}"); + + assertEquals("zipkin span should contain matching annotations for span logs", expectedValues, annotationValues); + } } diff --git a/jaeger-zipkin/src/test/java/com/uber/jaeger/senders/zipkin/ZipkinSenderTest.java b/jaeger-zipkin/src/test/java/com/uber/jaeger/senders/zipkin/ZipkinSenderTest.java index 39b215a22..8f6f2b47a 100644 --- a/jaeger-zipkin/src/test/java/com/uber/jaeger/senders/zipkin/ZipkinSenderTest.java +++ b/jaeger-zipkin/src/test/java/com/uber/jaeger/senders/zipkin/ZipkinSenderTest.java @@ -33,7 +33,11 @@ import com.uber.jaeger.reporters.Reporter; import com.uber.jaeger.samplers.ConstSampler; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import org.apache.thrift.transport.AutoExpandingBufferWriteTransport; import org.junit.After; import org.junit.Before; @@ -143,6 +147,43 @@ public void testFlushSendsSpan() throws Exception { } } + @Test + public void testAppendSpanWithLogs() throws Exception { + Span span = (Span) tracer.buildSpan("span-with-logs").startManual(); + + span.log("event"); + + // use sorted map for consistent ordering in test + Map fields = new TreeMap(); + fields.put("event", "structured data"); + fields.put("string", "something"); + fields.put("number", 42); + fields.put("boolean", true); + span.log(fields); + + sender.append(span); + sender.flush(); + + List> traces = zipkinRule.getTraces(); + assertEquals(1, traces.size()); + assertEquals(1, traces.get(0).size()); + + zipkin.Span zipkinSpan = traces.get(0).get(0); + assertEquals(2, zipkinSpan.annotations.size()); + + // ignore order by using set + Set annotationValues = new HashSet(); + for (Annotation annotation : zipkinSpan.annotations) { + annotationValues.add(annotation.value); + } + + Set expectedValues = new HashSet(); + expectedValues.add("event"); + expectedValues.add("{\"boolean\":true,\"event\":\"structured data\",\"number\":42,\"string\":\"something\"}"); + + assertEquals("zipkin span should contain matching annotations for span logs", expectedValues, annotationValues); + } + private ZipkinSender newSender(int messageMaxBytes) { return ZipkinSender.create( URLConnectionSender.builder()