use of zipkin2.Span.Kind.SERVER in project zipkin by openzipkin.
the class Trace method merge.
/*
* Spans can be sent in multiple parts. Also client and server spans can share the same ID. This
* merges both scenarios.
*/
public static List<Span> merge(List<Span> spans) {
int length = spans.size();
if (length <= 1)
return spans;
List<Span> result = new ArrayList<Span>(spans);
Collections.sort(result, CLEANUP_COMPARATOR);
// Let's cleanup any spans and pick the longest ID
String traceId = result.get(0).traceId();
for (int i = 1; i < length; i++) {
String nextTraceId = result.get(i).traceId();
if (traceId.length() != 32)
traceId = nextTraceId;
}
// Now start any fixes or merging
Span last = null;
for (int i = 0; i < length; i++) {
Span span = result.get(i);
// String previousId = last.id();
boolean spanShared = Boolean.TRUE.equals(span.shared());
// Choose the longest trace ID
Span.Builder replacement = null;
if (span.traceId().length() != traceId.length()) {
replacement = span.toBuilder().traceId(traceId);
}
EndpointTracker localEndpoint = null;
while (i + 1 < length) {
Span next = result.get(i + 1);
String nextId = next.id();
if (!nextId.equals(span.id()))
break;
if (localEndpoint == null) {
localEndpoint = new EndpointTracker();
localEndpoint.tryMerge(span.localEndpoint());
}
// This cautiously merges with the next span, if we think it was sent in multiple pieces.
boolean nextShared = Boolean.TRUE.equals(next.shared());
if (spanShared == nextShared && localEndpoint.tryMerge(next.localEndpoint())) {
if (replacement == null)
replacement = span.toBuilder();
replacement.merge(next);
// remove the merged element
length--;
result.remove(i + 1);
continue;
}
break;
}
// have the entire trace, and it is ordered client-first, we can correct a missing shared flag.
if (last != null && last.id().equals(span.id())) {
// Backfill missing shared flag as some instrumentation doesn't add it
if (last.kind() == Span.Kind.CLIENT && span.kind() == Span.Kind.SERVER && !spanShared) {
spanShared = true;
if (replacement == null)
replacement = span.toBuilder();
replacement.shared(true);
}
if (spanShared && span.parentId() == null && last.parentId() != null) {
// handle a shared RPC server span that wasn't propagated its parent span ID
if (replacement == null)
replacement = span.toBuilder();
replacement.parentId(last.parentId());
}
}
if (replacement != null) {
span = replacement.build();
result.set(i, span);
}
last = span;
}
return result;
}
use of zipkin2.Span.Kind.SERVER in project zipkin by openzipkin.
the class DependencyLinker method putTrace.
/**
* All {@code spans} must have the same trace id.
*/
public DependencyLinker putTrace(List<Span> spans) {
if (spans.isEmpty())
return this;
SpanNode traceTree = builder.build(spans);
if (logger.isLoggable(FINE))
logger.fine("traversing trace tree, breadth-first");
for (Iterator<SpanNode> i = traceTree.traverse(); i.hasNext(); ) {
SpanNode current = i.next();
Span currentSpan = current.span();
if (logger.isLoggable(FINE)) {
logger.fine("processing " + currentSpan);
}
Kind kind = currentSpan.kind();
// spans, we proceed to use the name the client chose.
if (Kind.CLIENT.equals(kind) && !current.children().isEmpty()) {
continue;
}
String serviceName = currentSpan.localServiceName();
String remoteServiceName = currentSpan.remoteServiceName();
if (kind == null) {
// Treat unknown type of span as a client span if we know both sides
if (serviceName != null && remoteServiceName != null) {
kind = Kind.CLIENT;
} else {
logger.fine("non remote span; skipping");
continue;
}
}
String child;
String parent;
switch(kind) {
case SERVER:
case CONSUMER:
child = serviceName;
parent = remoteServiceName;
if (current == traceTree) {
// we are the root-most span.
if (parent == null) {
logger.fine("root's client is unknown; skipping");
continue;
}
}
break;
case CLIENT:
case PRODUCER:
parent = serviceName;
child = remoteServiceName;
break;
default:
logger.fine("unknown kind; skipping");
continue;
}
boolean isError = currentSpan.tags().containsKey("error");
if (kind == Kind.PRODUCER || kind == Kind.CONSUMER) {
if (parent == null || child == null) {
logger.fine("cannot link messaging span to its broker; skipping");
} else {
addLink(parent, child, isError);
}
continue;
}
// Local spans may be between the current node and its remote parent
Span remoteAncestor = firstRemoteAncestor(current);
String remoteAncestorName;
if (remoteAncestor != null && (remoteAncestorName = remoteAncestor.localServiceName()) != null) {
// Check for this and backfill a link from the nearest remote to that service as necessary.
if (kind == Kind.CLIENT && serviceName != null && !remoteAncestorName.equals(serviceName)) {
logger.fine("detected missing link to client span");
// we don't know if there's an error here
addLink(remoteAncestorName, serviceName, false);
}
if (kind == Kind.SERVER || parent == null)
parent = remoteAncestorName;
// client, we need to check it for errors.
if (!isError && Kind.CLIENT.equals(remoteAncestor.kind()) && currentSpan.parentId() != null && currentSpan.parentId().equals(remoteAncestor.id())) {
isError = remoteAncestor.tags().containsKey("error");
}
}
if (parent == null || child == null) {
logger.fine("cannot find remote ancestor; skipping");
continue;
}
addLink(parent, child, isError);
}
return this;
}
use of zipkin2.Span.Kind.SERVER in project zipkin by openzipkin.
the class SpanConverterTest method redundantAddressAnnotations_client.
/**
* Intentionally create service loopback endpoints as dependency linker can correct it later if
* incorrect, provided the server is instrumented.
*/
@Test
public void redundantAddressAnnotations_client() {
Span v2 = Span.newBuilder().traceId("1").parentId("2").id("3").kind(Kind.CLIENT).name("get").localEndpoint(FRONTEND).remoteEndpoint(FRONTEND).timestamp(1472470996199000L).duration(207000L).build();
V1Span v1 = V1Span.newBuilder().traceId(1L).parentId(2L).id(3L).name("get").timestamp(1472470996199000L).duration(207000L).addAnnotation(1472470996199000L, "cs", FRONTEND).addAnnotation(1472470996406000L, "cr", FRONTEND).addBinaryAnnotation("ca", FRONTEND).addBinaryAnnotation("sa", FRONTEND).build();
assertThat(v1SpanConverter.convert(v1)).containsExactly(v2);
}
use of zipkin2.Span.Kind.SERVER in project zipkin by openzipkin.
the class DependencyLinkV2SpanIteratorTest method specialCasesFinagleLocalSocketLabeling_server.
@Test
public void specialCasesFinagleLocalSocketLabeling_server() {
DependencyLinkV2SpanIterator iterator = iterator(newRecord().values(traceIdHigh, traceId, parentId, spanId, "ca", TYPE_BOOLEAN, "service"), newRecord().values(traceIdHigh, traceId, parentId, spanId, "sa", TYPE_BOOLEAN, "service"), newRecord().values(traceIdHigh, traceId, parentId, spanId, "sr", -1, "service"));
Span span = iterator.next();
// When there is an "sr" annotation, we know it is a server
assertThat(span.kind()).isEqualTo(Span.Kind.SERVER);
assertThat(span.localServiceName()).isEqualTo("service");
assertThat(span.remoteEndpoint()).isNull();
}
use of zipkin2.Span.Kind.SERVER in project zipkin by openzipkin.
the class ITDependencies method getDependencies_linksMixedTraceId.
/**
* This tests that dependency linking ignores the high-bits of the trace ID when grouping spans
* for dependency links. This allows environments with 64-bit instrumentation to participate in
* the same trace as 128-bit instrumentation.
*/
@Test
protected void getDependencies_linksMixedTraceId(TestInfo testInfo) throws Exception {
String testSuffix = testSuffix(testInfo);
String traceId = newTraceId();
Endpoint frontend = suffixServiceName(TestObjects.FRONTEND, testSuffix);
Endpoint backend = suffixServiceName(TestObjects.BACKEND, testSuffix);
List<Span> mixedTrace = asList(Span.newBuilder().traceId(traceId).id("1").name("get").kind(Kind.SERVER).timestamp(TODAY * 1000L).duration(350 * 1000L).localEndpoint(frontend).build(), // the server dropped traceIdHigh
Span.newBuilder().traceId(traceId.substring(16)).parentId("1").id("2").name("get").kind(Kind.SERVER).shared(true).timestamp((TODAY + 100) * 1000L).duration(250 * 1000L).localEndpoint(backend).build(), Span.newBuilder().traceId(traceId).parentId("1").id("2").kind(Kind.CLIENT).timestamp((TODAY + 50) * 1000L).duration(300 * 1000L).localEndpoint(frontend).build());
processDependencies(mixedTrace);
assertThat(store().getDependencies(endTs(mixedTrace), DAY).execute()).containsOnly(DependencyLink.newBuilder().parent(frontend.serviceName()).child(backend.serviceName()).callCount(1).build());
}
Aggregations