use of zipkin.Span in project zipkin by openzipkin.
the class SpanStoreTest method correctsClockSkew.
/**
* Basic clock skew correction is something span stores should support, until the UI supports
* happens-before without using timestamps. The easiest clock skew to correct is where a child
* appears to happen before the parent.
*
* <p>It doesn't matter if clock-skew correction happens at store or query time, as long as it
* occurs by the time results are returned.
*
* <p>Span stores who don't support this can override and disable this test, noting in the README
* the limitation.
*/
@Test
public void correctsClockSkew() {
Endpoint client = Endpoint.create("client", 192 << 24 | 168 << 16 | 1);
Endpoint frontend = Endpoint.create("frontend", 192 << 24 | 168 << 16 | 2);
Endpoint backend = Endpoint.create("backend", 192 << 24 | 168 << 16 | 3);
/** Intentionally not setting span.timestamp, duration */
Span parent = Span.builder().traceId(1).name("method1").id(666).addAnnotation(Annotation.create((today + 100) * 1000, CLIENT_SEND, client)).addAnnotation(// before client sends
Annotation.create((today + 95) * 1000, SERVER_RECV, frontend)).addAnnotation(// before client receives
Annotation.create((today + 120) * 1000, SERVER_SEND, frontend)).addAnnotation(Annotation.create((today + 135) * 1000, CLIENT_RECV, client)).build();
/** Intentionally not setting span.timestamp, duration */
Span remoteChild = Span.builder().traceId(1).name("method2").id(777).parentId(666L).addAnnotation(Annotation.create((today + 100) * 1000, CLIENT_SEND, frontend)).addAnnotation(Annotation.create((today + 115) * 1000, SERVER_RECV, backend)).addAnnotation(Annotation.create((today + 120) * 1000, SERVER_SEND, backend)).addAnnotation(// before server sent
Annotation.create((today + 115) * 1000, CLIENT_RECV, frontend)).build();
/** Local spans must explicitly set timestamp */
Span localChild = Span.builder().traceId(1).name("local").id(778).parentId(666L).timestamp((today + 101) * 1000).duration(50L).addBinaryAnnotation(BinaryAnnotation.create(LOCAL_COMPONENT, "framey", frontend)).build();
List<Span> skewed = asList(parent, remoteChild, localChild);
// There's clock skew when the child doesn't happen after the parent
assertThat(skewed.get(0).annotations.get(0).timestamp).isLessThanOrEqualTo(skewed.get(1).annotations.get(0).timestamp).isLessThanOrEqualTo(// local span
skewed.get(2).timestamp);
// Regardless of when clock skew is corrected, it should be corrected before traces return
accept(parent, remoteChild, localChild);
List<Span> adjusted = store().getTrace(localChild.traceIdHigh, localChild.traceId);
// After correction, the child happens after the parent
assertThat(adjusted.get(0).timestamp).isLessThanOrEqualTo(adjusted.get(0).timestamp);
// After correction, children happen after their parent
assertThat(adjusted.get(0).timestamp).isLessThanOrEqualTo(adjusted.get(1).timestamp).isLessThanOrEqualTo(adjusted.get(2).timestamp);
// And we do not change the parent (client) duration, due to skew in the child (server)
assertThat(adjusted.get(0).duration).isEqualTo(clientDuration(skewed.get(0)));
assertThat(adjusted.get(1).duration).isEqualTo(clientDuration(skewed.get(1)));
assertThat(adjusted.get(2).duration).isEqualTo(skewed.get(2).duration);
}
use of zipkin.Span in project zipkin by openzipkin.
the class SpanStoreTest method getTraces_mergesSpans.
/**
* It is expected that [[com.twitter.zipkin.storage.SpanStore.apply]] will receive the same span
* id multiple times with different annotations. At query time, these must be merged.
*/
@Test
public void getTraces_mergesSpans() {
// span4, span5 have the same span id
accept(span1, span4, span5);
SortedSet<Annotation> mergedAnnotations = new TreeSet<>(span4.annotations);
mergedAnnotations.addAll(span5.annotations);
Span merged = span4.toBuilder().timestamp(mergedAnnotations.first().timestamp).duration(mergedAnnotations.last().timestamp - mergedAnnotations.first().timestamp).annotations(mergedAnnotations).binaryAnnotations(span5.binaryAnnotations).build();
assertThat(store().getTraces(QueryRequest.builder().serviceName("service").build())).containsExactly(asList(merged), asList(span1));
}
use of zipkin.Span in project zipkin by openzipkin.
the class SpanStoreTest method getTraces_duration.
/** Shows that duration queries go against the root span, not the child */
@Test
public void getTraces_duration() {
Endpoint service1 = Endpoint.create("service1", 127 << 24 | 1);
Endpoint service2 = Endpoint.create("service2", 127 << 24 | 2);
Endpoint service3 = Endpoint.create("service3", 127 << 24 | 3);
BinaryAnnotation.Builder component = BinaryAnnotation.builder().key(LOCAL_COMPONENT).value("archiver");
BinaryAnnotation archiver1 = component.endpoint(service1).build();
BinaryAnnotation archiver2 = component.endpoint(service2).build();
BinaryAnnotation archiver3 = component.endpoint(service3).build();
Span targz = Span.builder().traceId(1L).id(1L).name("targz").timestamp(today * 1000 + 100L).duration(200L).addBinaryAnnotation(archiver1).build();
Span tar = Span.builder().traceId(1L).id(2L).parentId(1L).name("tar").timestamp(today * 1000 + 200L).duration(150L).addBinaryAnnotation(archiver2).build();
Span gz = Span.builder().traceId(1L).id(3L).parentId(1L).name("gz").timestamp(today * 1000 + 250L).duration(50L).addBinaryAnnotation(archiver3).build();
Span zip = Span.builder().traceId(3L).id(3L).name("zip").timestamp(today * 1000 + 130L).duration(50L).addBinaryAnnotation(archiver2).build();
List<Span> trace1 = asList(targz, tar, gz);
List<Span> trace2 = asList(targz.toBuilder().traceId(2L).timestamp(today * 1000 + 110L).binaryAnnotations(asList(archiver3)).build(), tar.toBuilder().traceId(2L).timestamp(today * 1000 + 210L).binaryAnnotations(asList(archiver2)).build(), gz.toBuilder().traceId(2L).timestamp(today * 1000 + 260L).binaryAnnotations(asList(archiver1)).build());
List<Span> trace3 = asList(zip);
accept(trace1.toArray(new Span[0]));
accept(trace2.toArray(new Span[0]));
accept(trace3.toArray(new Span[0]));
// 12hrs, instead of 7days
long lookback = 12L * 60 * 60 * 1000;
// greater than all timestamps above
long endTs = today + 1;
QueryRequest.Builder q = QueryRequest.builder().serviceName("service1").lookback(lookback).endTs(endTs);
// Min duration is inclusive and is applied by service.
assertThat(store().getTraces(q.serviceName("service1").minDuration(targz.duration).build())).containsExactly(trace1);
assertThat(store().getTraces(q.serviceName("service3").minDuration(targz.duration).build())).containsExactly(trace2);
// Duration bounds aren't limited to root spans: they apply to all spans by service in a trace
assertThat(store().getTraces(q.serviceName("service2").minDuration(zip.duration).maxDuration(tar.duration).build())).containsExactly(trace3, trace2, // service2 is in the middle of trace1 and 2, but root of trace3
trace1);
// Span name should apply to the duration filter
assertThat(store().getTraces(q.serviceName("service2").spanName("zip").maxDuration(zip.duration).build())).containsExactly(trace3);
// Max duration should filter our longer spans from the same service
assertThat(store().getTraces(q.serviceName("service2").minDuration(gz.duration).maxDuration(zip.duration).build())).containsExactly(trace3);
}
use of zipkin.Span in project zipkin by openzipkin.
the class SpanStoreTest method getTraces_differentiateOnServiceName.
/**
* This test makes sure that annotation queries pay attention to which host logged an annotation.
*/
@Test
public void getTraces_differentiateOnServiceName() {
Span trace1 = Span.builder().traceId(1).name("get").id(1).timestamp((today + 1) * 1000).addAnnotation(Annotation.create((today + 1) * 1000, CLIENT_SEND, WEB_ENDPOINT)).addAnnotation(Annotation.create((today + 1) * 1000, SERVER_RECV, APP_ENDPOINT)).addAnnotation(Annotation.create((today + 1) * 1000, SERVER_SEND, APP_ENDPOINT)).addAnnotation(Annotation.create((today + 1) * 1000, CLIENT_RECV, WEB_ENDPOINT)).addAnnotation(Annotation.create((today + 1) * 1000, "web", WEB_ENDPOINT)).addBinaryAnnotation(BinaryAnnotation.create("local", "web", WEB_ENDPOINT)).addBinaryAnnotation(BinaryAnnotation.create("web-b", "web", WEB_ENDPOINT)).build();
Span trace2 = Span.builder().traceId(2).name("get").id(2).timestamp((today + 2) * 1000).addAnnotation(Annotation.create((today + 1) * 1000, CLIENT_SEND, APP_ENDPOINT)).addAnnotation(Annotation.create((today + 1) * 1000, SERVER_RECV, WEB_ENDPOINT)).addAnnotation(Annotation.create((today + 1) * 1000, SERVER_SEND, WEB_ENDPOINT)).addAnnotation(Annotation.create((today + 1) * 1000, CLIENT_RECV, APP_ENDPOINT)).addAnnotation(Annotation.create((today + 1) * 1000, "app", APP_ENDPOINT)).addBinaryAnnotation(BinaryAnnotation.create("local", "app", APP_ENDPOINT)).addBinaryAnnotation(BinaryAnnotation.create("app-b", "app", APP_ENDPOINT)).build();
accept(trace1, trace2);
assertThat(store().getTraces(QueryRequest.builder().build())).containsExactly(asList(trace2), asList(trace1));
// We only return traces where the service specified caused the annotation queried.
assertThat(store().getTraces(QueryRequest.builder().serviceName("web").addAnnotation("web").build())).containsExactly(asList(trace1));
assertThat(store().getTraces(QueryRequest.builder().serviceName("app").addAnnotation("web").build())).isEmpty();
assertThat(store().getTraces(QueryRequest.builder().serviceName("app").addAnnotation("app").build())).containsExactly(asList(trace2));
assertThat(store().getTraces(QueryRequest.builder().serviceName("web").addAnnotation("app").build())).isEmpty();
// Binary annotations are not returned for annotation queries
assertThat(store().getTraces(QueryRequest.builder().serviceName("web").addAnnotation("web-b").build())).isEmpty();
assertThat(store().getTraces(QueryRequest.builder().serviceName("app").addAnnotation("web-b").build())).isEmpty();
assertThat(store().getTraces(QueryRequest.builder().serviceName("app").addAnnotation("app-b").build())).isEmpty();
assertThat(store().getTraces(QueryRequest.builder().serviceName("web").addAnnotation("app-b").build())).isEmpty();
// We only return traces where the service specified caused the binary value queried.
assertThat(store().getTraces(QueryRequest.builder().serviceName("web").addBinaryAnnotation("local", "web").build())).containsExactly(asList(trace1));
assertThat(store().getTraces(QueryRequest.builder().serviceName("app").addBinaryAnnotation("local", "web").build())).isEmpty();
assertThat(store().getTraces(QueryRequest.builder().serviceName("app").addBinaryAnnotation("local", "app").build())).containsExactly(asList(trace2));
assertThat(store().getTraces(QueryRequest.builder().serviceName("web").addBinaryAnnotation("local", "app").build())).isEmpty();
}
use of zipkin.Span in project zipkin by openzipkin.
the class SpanStoreTest method rawTrace_doesntPerformQueryTimeAdjustment.
// This supports the "raw trace" feature, which skips application-level data cleaning
@Test
public void rawTrace_doesntPerformQueryTimeAdjustment() {
Endpoint producer = Endpoint.create("producer", 192 << 24 | 168 << 16 | 1);
Annotation ms = Annotation.create((today + 95) * 1000, "ms", producer);
Endpoint consumer = Endpoint.create("consumer", 192 << 24 | 168 << 16 | 2);
Annotation mr = Annotation.create((today + 100) * 1000, "mr", consumer);
Span span = Span.builder().traceId(1).name("message").id(666).build();
// Simulate instrumentation that sends annotations one at-a-time.
// This should prevent the collection tier from being able to calculate duration.
accept(span.toBuilder().addAnnotation(ms).build());
accept(span.toBuilder().addAnnotation(mr).build());
// Normally, span store implementations will merge spans by id and add duration by query time
assertThat(store().getTrace(span1.traceIdHigh, span.traceId)).containsExactly(span.toBuilder().timestamp(ms.timestamp).duration(mr.timestamp - ms.timestamp).annotations(asList(ms, mr)).build());
// Since a collector never saw both sides of the span, we'd not see duration in the raw trace.
for (Span raw : store().getRawTrace(span1.traceIdHigh, span.traceId)) {
assertThat(raw.timestamp).isNull();
assertThat(raw.duration).isNull();
}
}
Aggregations