use of zipkin.Annotation in project zipkin by openzipkin.
the class ApplyTimestampAndDuration method apply.
/**
* For RPC two-way spans, the duration between "cs" and "cr" is authoritative. RPC one-way spans
* lack a response, so the duration is between "cs" and "sr". We special-case this to avoid
* setting incorrect duration when there's skew between the client and the server.
*
* <p>Note: this should only be used for query, not storage commands!
*/
public static Span apply(Span span) {
// Don't overwrite authoritatively set timestamp and duration!
if (span.timestamp != null && span.duration != null) {
return span;
}
// backfill timestamp.
if (span.annotations.size() < 2) {
if (span.timestamp != null)
return span;
Long guess = guessTimestamp(span);
if (guess == null)
return span;
return span.toBuilder().timestamp(guess).build();
}
// Prefer RPC one-way (cs -> sr) vs arbitrary annotations.
Long first = span.annotations.get(0).timestamp;
Long last = span.annotations.get(span.annotations.size() - 1).timestamp;
for (int i = 0, length = span.annotations.size(); i < length; i++) {
Annotation annotation = span.annotations.get(i);
if (annotation.value.equals(Constants.CLIENT_SEND)) {
first = annotation.timestamp;
} else if (annotation.value.equals(Constants.CLIENT_RECV)) {
last = annotation.timestamp;
}
}
long ts = span.timestamp != null ? span.timestamp : first;
Long dur = span.duration != null ? span.duration : last.equals(first) ? null : last - first;
return span.toBuilder().timestamp(ts).duration(dur).build();
}
use of zipkin.Annotation in project zipkin by openzipkin.
the class ApplyTimestampAndDuration method guessTimestamp.
/**
* Instrumentation should set {@link Span#timestamp} when recording a span so that guess-work
* isn't needed. Since a lot of instrumentation don't, we have to make some guesses.
*
* <pre><ul>
* <li>If there is a {@link Constants#CLIENT_SEND}, use that</li>
* <li>Fall back to {@link Constants#SERVER_RECV}, if a root span</li>
* <li>Otherwise, return null</li>
* </ul></pre>
*/
public static Long guessTimestamp(Span span) {
if (span.timestamp != null || span.annotations.isEmpty())
return span.timestamp;
boolean isRoot = span.parentId == null;
Long rootServerRecv = null;
for (int i = 0, length = span.annotations.size(); i < length; i++) {
Annotation annotation = span.annotations.get(i);
if (annotation.value.equals(Constants.CLIENT_SEND)) {
return annotation.timestamp;
} else if (annotation.value.equals(Constants.SERVER_RECV) && isRoot) {
rootServerRecv = annotation.timestamp;
}
}
return rootServerRecv;
}
use of zipkin.Annotation 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.Annotation 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();
}
}
use of zipkin.Annotation in project zipkin by openzipkin.
the class ZipkinServerTest method readsBackSpanName.
@Test
public void readsBackSpanName() throws Exception {
String service = "web";
Endpoint endpoint = Endpoint.create(service, 127 << 24 | 1, 80);
Annotation ann = Annotation.create(System.currentTimeMillis() * 1000, SERVER_RECV, endpoint);
Span span = Span.builder().id(1L).traceId(1L).name("get").addAnnotation(ann).build();
// write the span to the server
performAsync(post("/api/v1/spans").content(Codec.JSON.writeSpans(asList(span)))).andExpect(status().isAccepted());
// sleep as the the storage operation is async
Thread.sleep(1000);
// read back the span name, given its service
mockMvc.perform(get("/api/v1/spans?serviceName=" + service)).andExpect(status().isOk()).andExpect(content().string("[\"" + span.name + "\"]"));
}
Aggregations