diff --git a/jaeger-core/src/main/java/com/uber/jaeger/Constants.java b/jaeger-core/src/main/java/com/uber/jaeger/Constants.java index 438e6e354..5f7bbf45a 100644 --- a/jaeger-core/src/main/java/com/uber/jaeger/Constants.java +++ b/jaeger-core/src/main/java/com/uber/jaeger/Constants.java @@ -42,4 +42,19 @@ public class Constants { * root span, so that the trace can be found in the UI using this value as a correlation ID. */ public static final String DEBUG_ID_HEADER_KEY = "jaeger-debug-id"; + + /** + * The name of the tag used to report client version. + */ + public static final String JAEGER_CLIENT_VERSION_TAG_KEY = "jaeger.version"; + + /** + * The name used to report host name of the process. + */ + public static final String TRACER_HOSTNAME_TAG_KEY = "hostname"; + + /** + * The name used to report ip of the process. + */ + public static final String TRACER_IP_TAG_KEY = "ip"; } diff --git a/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java b/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java index 682491cb4..7724a3ac3 100644 --- a/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java +++ b/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java @@ -22,6 +22,7 @@ package com.uber.jaeger; +import com.uber.jaeger.Constants; import com.uber.jaeger.exceptions.UnsupportedFormatException; import com.uber.jaeger.metrics.Metrics; import com.uber.jaeger.metrics.NullStatsReporter; @@ -69,7 +70,7 @@ public class Tracer implements io.opentracing.Tracer { private final PropagationRegistry registry; private final Clock clock; private final Metrics metrics; - private final int ip; + private final int ipv4; private final Map tags; private final boolean zipkinSharedRpcSpan; private final ActiveSpanSource activeSpanSource; @@ -93,21 +94,21 @@ private Tracer( this.zipkinSharedRpcSpan = zipkinSharedRpcSpan; this.activeSpanSource = activeSpanSource; - int ip; - try { - ip = Utils.ipToInt(Inet4Address.getLocalHost().getHostAddress()); - } catch (UnknownHostException e) { - ip = 0; - } - this.ip = ip; - this.version = loadVersion(); - tags.put("jaeger.version", this.version); + tags.put(Constants.JAEGER_CLIENT_VERSION_TAG_KEY, this.version); String hostname = getHostName(); if (hostname != null) { - tags.put("jaeger.hostname", hostname); + tags.put(Constants.TRACER_HOSTNAME_TAG_KEY, hostname); } + int ipv4 ; + try { + tags.put(Constants.TRACER_IP_TAG_KEY, InetAddress.getLocalHost().getHostAddress()); + ipv4 = Utils.ipToInt(Inet4Address.getLocalHost().getHostAddress()); + } catch (UnknownHostException e) { + ipv4 = 0; + } + this.ipv4 = ipv4; this.tags = Collections.unmodifiableMap(tags); } @@ -127,8 +128,8 @@ public String getServiceName() { return tags; } - public int getIp() { - return ip; + public int getIpv4() { + return ipv4; } Clock clock() { @@ -397,11 +398,6 @@ public io.opentracing.Span startManual() { } } - // TODO move this to jaeger-zipkin, this adds tracer tags to zipkin first span in a process - if (zipkinSharedRpcSpan && (references.isEmpty() || isRpcServer())) { - tags.putAll(Tracer.this.tags); - } - Span span = new Span( Tracer.this, @@ -557,7 +553,7 @@ private static String loadVersion() { try { Properties prop = new Properties(); prop.load(is); - version = prop.getProperty("jaeger.version"); + version = prop.getProperty(Constants.JAEGER_CLIENT_VERSION_TAG_KEY); } finally { is.close(); } @@ -565,7 +561,7 @@ private static String loadVersion() { throw new RuntimeException("Cannot read jaeger.properties", e); } if (version == null) { - throw new RuntimeException("Cannot read jaeger.version from jaeger.properties"); + throw new RuntimeException("Cannot read " + Constants.JAEGER_CLIENT_VERSION_TAG_KEY + " from jaeger.properties"); } return "Java-" + version; } diff --git a/jaeger-core/src/test/java/com/uber/jaeger/TracerTagsTest.java b/jaeger-core/src/test/java/com/uber/jaeger/TracerTagsTest.java index 77227760f..ebc796297 100644 --- a/jaeger-core/src/test/java/com/uber/jaeger/TracerTagsTest.java +++ b/jaeger-core/src/test/java/com/uber/jaeger/TracerTagsTest.java @@ -23,115 +23,27 @@ package com.uber.jaeger; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import com.uber.jaeger.reporters.InMemoryReporter; import com.uber.jaeger.samplers.ConstSampler; -import io.opentracing.tag.Tags; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -@RunWith(Parameterized.class) public class TracerTagsTest { - private enum SpanType { - ROOT, - CHILD, - RPC_SERVER - } - - // sentinel value is used to mark tags that should *not* be present - private static final Object SENTINEL = new Object(); - - private final SpanType spanType; - private final Map expectedTags; - - public TracerTagsTest(SpanType spanType, Map expectedTags) { - this.spanType = spanType; - this.expectedTags = expectedTags; - } - - @Parameterized.Parameters(name = "{index}: {0}") - public static Collection data() { - Tracer tracer = new Tracer.Builder("x", null, null).build(); - String hostname = tracer.getHostName(); - - Map rootTags = new HashMap<>(); - rootTags.put("jaeger.version", tracer.getVersion()); - rootTags.put("jaeger.hostname", hostname); - rootTags.put("tracer.tag.str", "y"); - rootTags.put("tracer.tag.bool", true); - rootTags.put("tracer.tag.num", 1); - rootTags.put("sampler.type", "const"); - rootTags.put("sampler.param", true); - - Map childTags = new HashMap<>(); - childTags.put("jaeger.version", SENTINEL); - childTags.put("jaeger.hostname", SENTINEL); - childTags.put("tracer.tag.str", SENTINEL); - childTags.put("tracer.tag.bool", SENTINEL); - childTags.put("tracer.tag.num", SENTINEL); - childTags.put("sampler.type", SENTINEL); - childTags.put("sampler.param", SENTINEL); - - Map rpcTags = new HashMap<>(); - rpcTags.put("jaeger.version", tracer.getVersion()); - rpcTags.put("jaeger.hostname", hostname); - rpcTags.put("tracer.tag.str", "y"); - rpcTags.put("tracer.tag.bool", true); - rpcTags.put("tracer.tag.num", 1); - rpcTags.put("sampler.type", SENTINEL); - rpcTags.put("sampler.param", SENTINEL); - - List data = new ArrayList<>(); - data.add(new Object[] {SpanType.ROOT, rootTags}); - data.add(new Object[] {SpanType.CHILD, childTags}); - data.add(new Object[] {SpanType.RPC_SERVER, rpcTags}); - return data; - } - - @Before - public void setUp() throws Exception {} - @Test - public void testTracerTagsZipkin() throws Exception { + public void testTracerTags() throws Exception { InMemoryReporter spanReporter = new InMemoryReporter(); Tracer tracer = new Tracer.Builder("x", spanReporter, new ConstSampler(true)) - .withZipkinSharedRpcSpan() - .withTag("tracer.tag.str", "y") - .withTag("tracer.tag.bool", true) - .withTag("tracer.tag.num", 1) - .build(); + .withZipkinSharedRpcSpan() + .withTag("tracer.tag.str", "y") + .build(); Span span = (Span) tracer.buildSpan("root").startManual(); - if (spanType == SpanType.CHILD) { - span = (Span) tracer.buildSpan("child").asChildOf(span).startManual(); - } - if (spanType == SpanType.RPC_SERVER) { - span = - (Span) - tracer - .buildSpan("rpc-server") - .asChildOf(span) - .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) - .startManual(); - } - Map tags = span.getTags(); - for (String key : expectedTags.keySet()) { - Object expectedValue = expectedTags.get(key); - Object actualValue = tags.get(key); - if (expectedValue == SENTINEL) { - assertNull("Not expecting " + key + " for " + spanType, actualValue); - } else { - assertEquals("Expecting " + key + " for " + spanType, expectedValue, actualValue); - } - } + + // span should only contain sampler tags and no tracer tags + assertEquals(2, span.getTags().size()); + assertEquals(true, span.getTags().containsKey("sampler.type")); + assertEquals(true, span.getTags().containsKey("sampler.param")); + assertEquals(false, span.getTags().containsKey("tracer.tag.str")); } } diff --git a/jaeger-core/src/test/java/com/uber/jaeger/senders/UdpSenderTest.java b/jaeger-core/src/test/java/com/uber/jaeger/senders/UdpSenderTest.java index c33d67168..613c93cd1 100644 --- a/jaeger-core/src/test/java/com/uber/jaeger/senders/UdpSenderTest.java +++ b/jaeger-core/src/test/java/com/uber/jaeger/senders/UdpSenderTest.java @@ -170,10 +170,11 @@ public void testFlushSendsSpan() throws Exception { assertEquals(0, actualSpan.getParentSpanId()); assertTrue(actualSpan.references.isEmpty()); assertEquals(expectedSpan.getOperationName(), actualSpan.getOperationName()); - assertEquals(3, batch.getProcess().getTags().size()); - assertEquals("jaeger.hostname", batch.getProcess().getTags().get(0).getKey()); + assertEquals(4, batch.getProcess().getTags().size()); + assertEquals("hostname", batch.getProcess().getTags().get(0).getKey()); assertEquals("jaeger.version", batch.getProcess().getTags().get(1).getKey()); assertEquals("bar", batch.getProcess().getTags().get(2).getVStr()); + assertEquals("ip", batch.getProcess().getTags().get(3).getKey()); } @Test diff --git a/jaeger-zipkin/build.gradle b/jaeger-zipkin/build.gradle index 8d6931d43..e027cd408 100644 --- a/jaeger-zipkin/build.gradle +++ b/jaeger-zipkin/build.gradle @@ -9,6 +9,7 @@ dependencies { testCompile group: 'junit', name: 'junit', version: junitVersion testCompile group: 'io.zipkin.java', name: 'zipkin-junit', version: '1.16.2' testCompile group: 'io.zipkin.brave', name: 'brave-http', version: '4.1.1' + testCompile group: 'com.tngtech.java', name: 'junit-dataprovider', version: junitDataProviderVersion signature 'org.codehaus.mojo.signature:java16:1.1@signature' } 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 882be0e2d..56756cadb 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 @@ -27,6 +27,7 @@ import com.twitter.zipkin.thriftjava.BinaryAnnotation; import com.twitter.zipkin.thriftjava.Endpoint; import com.twitter.zipkin.thriftjava.zipkincoreConstants; +import com.uber.jaeger.Constants; import com.uber.jaeger.LogData; import com.uber.jaeger.Span; import com.uber.jaeger.SpanContext; @@ -34,6 +35,7 @@ import io.opentracing.tag.Tags; import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -43,7 +45,7 @@ public class ThriftSpanConverter { public static com.twitter.zipkin.thriftjava.Span convertSpan(Span span) { Tracer tracer = span.getTracer(); - Endpoint host = new Endpoint(tracer.getIp(), (short) 0, tracer.getServiceName()); + Endpoint host = new Endpoint(tracer.getIpv4(), (short) 0, tracer.getServiceName()); SpanContext context = span.context(); return new com.twitter.zipkin.thriftjava.Span( @@ -88,6 +90,20 @@ private static List buildBinaryAnnotations(Span span, Endpoint Map tags = span.getTags(); boolean isRpc = isRpc(span); boolean isClient = isRpcClient(span); + boolean firstSpanInProcess = span.getReferences().isEmpty() || isRpcServer(span); + + if (firstSpanInProcess) { + Map processTags = span.getTracer().tags(); + // add tracer tags to first zipkin span in a process but remove "ip" tag as it is + // taken care of separately. + for (String tagKey : processTags.keySet()) { + if (!tagKey.equals(Constants.TRACER_IP_TAG_KEY)) { + Object tagValue = processTags.get(tagKey); + // add a tracer. prefix to process tags for zipkin + binaryAnnotations.add(buildBinaryAnnotation("tracer." + tagKey, tagValue)); + } + } + } Endpoint peerEndpoint = extractPeerEndpoint(tags); if (peerEndpoint != null && isClient) { @@ -137,13 +153,17 @@ private static BinaryAnnotation buildBinaryAnnotation(String tagKey, Object tagV return banno; } - public static boolean isRpc(Span span) { + static boolean isRpcServer(Span span) { + return Tags.SPAN_KIND_SERVER.equals(span.getTags().get(Tags.SPAN_KIND.getKey())); + } + + static boolean isRpc(Span span) { Object spanKindValue = span.getTags().get(Tags.SPAN_KIND.getKey()); return Tags.SPAN_KIND_CLIENT.equals(spanKindValue) || Tags.SPAN_KIND_SERVER.equals(spanKindValue); } - public static boolean isRpcClient(Span span) { + static boolean isRpcClient(Span span) { return Tags.SPAN_KIND_CLIENT.equals(span.getTags().get(Tags.SPAN_KIND.getKey())); } 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 653fd650b..37aa4b84f 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 @@ -25,8 +25,13 @@ import static junit.framework.TestCase.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; import com.twitter.zipkin.thriftjava.Annotation; +import com.twitter.zipkin.thriftjava.BinaryAnnotation; import com.twitter.zipkin.thriftjava.zipkincoreConstants; import com.uber.jaeger.Span; import com.uber.jaeger.SpanContext; @@ -42,9 +47,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +@RunWith(DataProviderRunner.class) public class ThriftSpanConverterTest { Tracer tracer; @@ -56,6 +64,105 @@ public void setUp() { .build(); } + // undef value is used to mark tags that should *not* be present + private static final String UNDEF = "undef"; + + // ANY value is used to mark tags that should be present but we don't care what it's value is + private static final String ANY = "any"; + + private enum SpanType { + ROOT, + CHILD, + RPC_SERVER + } + + @DataProvider + public static Object[][] dataProviderTracerTags() { + Tracer tracer = new Tracer.Builder("x", null, null).build(); + + Map rootTags = new HashMap<>(); + rootTags.put("tracer.jaeger.version", tracer.getVersion()); + rootTags.put("tracer.hostname", ANY); + rootTags.put("tracer.tag.str", "y"); + rootTags.put("tracer.tag.bool", "true"); + rootTags.put("tracer.tag.num", "1"); + rootTags.put("sampler.type", "const"); + rootTags.put("sampler.param", "true"); + + Map childTags = new HashMap<>(); + childTags.put("tracer.jaeger.version", UNDEF); + childTags.put("tracer.hostname", UNDEF); + childTags.put("tracer.tag.str", UNDEF); + childTags.put("tracer.tag.bool", UNDEF); + childTags.put("tracer.tag.num", UNDEF); + childTags.put("sampler.type", UNDEF); + childTags.put("sampler.param", UNDEF); + + Map rpcTags = new HashMap<>(); + rpcTags.put("tracer.jaeger.version", tracer.getVersion()); + rpcTags.put("tracer.hostname", ANY); + rpcTags.put("tracer.tag.str", "y"); + rpcTags.put("tracer.tag.bool", "true"); + rpcTags.put("tracer.tag.num", "1"); + rpcTags.put("sampler.type", UNDEF); + rpcTags.put("sampler.param", UNDEF); + + return new Object[][] { + { SpanType.ROOT, rootTags }, + { SpanType.CHILD, childTags }, + { SpanType.RPC_SERVER, rpcTags }, + }; + } + + @Test + @UseDataProvider("dataProviderTracerTags") + public void testTracerTags(SpanType spanType, Map expectedTags) throws Exception { + InMemoryReporter spanReporter = new InMemoryReporter(); + Tracer tracer = new Tracer.Builder("x", spanReporter, new ConstSampler(true)) + .withZipkinSharedRpcSpan() + .withTag("tag.str", "y") + .withTag("tag.bool", true) + .withTag("tag.num", 1) + .build(); + + Span span = (Span) tracer.buildSpan("root").startManual(); + if (spanType == SpanType.CHILD) { + span = (Span) tracer.buildSpan("child").asChildOf(span).startManual(); + } else if (spanType == SpanType.RPC_SERVER) { + span = + (Span) + tracer + .buildSpan("rpc-server") + .asChildOf(span) + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) + .startManual(); + } + com.twitter.zipkin.thriftjava.Span zipkinSpan = ThriftSpanConverter.convertSpan(span); + + List annotations = zipkinSpan.getBinary_annotations();; + for (String key : expectedTags.keySet()) { + Object expectedValue = expectedTags.get(key); + BinaryAnnotation anno = findBinaryAnnotation(annotations, key); + if (expectedValue.equals(UNDEF)) { + assertNull("Not expecting " + key + " for " + spanType, anno); + } else if (expectedValue.equals(ANY)) { + assertEquals(key, anno.getKey()); + } else { + String actualValue = new String(anno.getValue(), StandardCharsets.UTF_8); + assertEquals("Expecting " + key + " for " + spanType, expectedValue, actualValue); + } + } + } + + private BinaryAnnotation findBinaryAnnotation(List annotations, String key) { + for (BinaryAnnotation anno : annotations) { + if (anno.getKey().equals(key)) { + return anno; + } + } + return null; + } + @Test public void testSpanKindServerCreatesAnnotations() { Span span = (com.uber.jaeger.Span) tracer.buildSpan("operation-name").startManual(); @@ -70,12 +177,10 @@ public void testSpanKindServerCreatesAnnotations() { if (anno.getValue().equals(zipkincoreConstants.SERVER_RECV)) { serverReceiveFound = true; } - if (anno.getValue().equals(zipkincoreConstants.SERVER_SEND)) { serverSendFound = true; } } - assertTrue(serverReceiveFound); assertTrue(serverSendFound); } @@ -105,15 +210,15 @@ public void testSpanKindClientCreatesAnnotations() { } @Test - public void testExpectdLocalComponentNameUsed() { - String expectedCompnentName = "local-name"; + public void testExpectedLocalComponentNameUsed() { + String expectedComponentName = "local-name"; Span span = (com.uber.jaeger.Span) tracer.buildSpan("operation-name").startManual(); - Tags.COMPONENT.set(span, expectedCompnentName); + Tags.COMPONENT.set(span, expectedComponentName); com.twitter.zipkin.thriftjava.Span zipkinSpan = ThriftSpanConverter.convertSpan(span); String actualComponent = - new String(zipkinSpan.getBinary_annotations().get(0).getValue(), StandardCharsets.UTF_8); - assertEquals(expectedCompnentName, actualComponent); + new String(zipkinSpan.getBinary_annotations().get(3).getValue(), StandardCharsets.UTF_8); + assertEquals(expectedComponentName, actualComponent); } @Test