use of zipkin.BinaryAnnotation in project zipkin by openzipkin.
the class CassandraSpanConsumer method storeSpan.
/**
* Store the span in the underlying storage for later retrieval.
*/
ListenableFuture<?> storeSpan(Span span, TraceIdUDT traceId, boolean isServerRecvSpan, Long timestamp) {
try {
if ((null == timestamp || 0 == timestamp) && !isServerRecvSpan && metadata.compactionClass.contains("TimeWindowCompactionStrategy")) {
LOG.warn("Span {} in trace {} had no timestamp. " + "If this happens a lot consider switching back to SizeTieredCompactionStrategy for " + "{}.traces", span.id, span.traceId, session.getLoggedKeyspace());
}
List<AnnotationUDT> annotations = new ArrayList<>(span.annotations.size());
for (Annotation annotation : span.annotations) {
annotations.add(new AnnotationUDT(annotation));
}
List<BinaryAnnotationUDT> binaryAnnotations = new ArrayList<>(span.binaryAnnotations.size());
for (BinaryAnnotation annotation : span.binaryAnnotations) {
binaryAnnotations.add(new BinaryAnnotationUDT(annotation));
}
Set<String> annotationKeys = CassandraUtil.annotationKeys(span);
if (!strictTraceId && traceId.getHigh() != 0L) {
storeSpan(span, new TraceIdUDT(0L, traceId.getLow()), isServerRecvSpan, timestamp);
}
BoundStatement bound = bindWithName(insertSpan, "insert-span").set("trace_id", traceId, TraceIdUDT.class).setUUID("ts_uuid", new UUID(UUIDs.startOf(null != timestamp ? (timestamp / 1000) : 0).getMostSignificantBits(), UUIDs.random().getLeastSignificantBits())).setLong("id", span.id).setString("span_name", span.name).setList("annotations", annotations).setList("binary_annotations", binaryAnnotations).setString("all_annotations", Joiner.on(',').join(annotationKeys));
if (null != span.timestamp) {
bound = bound.setLong("ts", span.timestamp);
}
if (null != span.duration) {
bound = bound.setLong("duration", span.duration);
}
if (null != span.parentId) {
bound = bound.setLong("parent_id", span.parentId);
}
return session.executeAsync(bound);
} catch (RuntimeException ex) {
return Futures.immediateFailedFuture(ex);
}
}
use of zipkin.BinaryAnnotation in project zipkin by openzipkin.
the class CassandraUtil method annotationKeys.
/**
* Returns keys that concatenate the serviceName associated with an annotation or a binary
* annotation.
*
* <p>Note: Annotations are delimited with colons while Binary Annotations are delimited with
* semi-colons. This is because the returned keys are joined on comma and queried with LIKE. For
* example, a span with the annotation "foo" and a binary annotation "bar" -> "baz" would end up
* in a cell "service:foo,service:bar:baz". A query for the annotation "bar" would satisfy as
* "service:bar" is a substring of that cell. This is imprecise. By joining binary annotations on
* semicolon, this mismatch cannot happen.
*
* <p>Note: in the case of binary annotations, only string types are returned, as that's the only
* queryable type, per {@link QueryRequest#binaryAnnotations}.
*
* @see QueryRequest#annotations
* @see QueryRequest#binaryAnnotations
*/
static Set<String> annotationKeys(Span span) {
Set<String> annotationKeys = new LinkedHashSet<>();
for (Annotation a : span.annotations) {
// don't index core annotations as they aren't queryable
if (Constants.CORE_ANNOTATIONS.contains(a.value))
continue;
if (a.endpoint != null && !a.endpoint.serviceName.isEmpty()) {
annotationKeys.add(a.endpoint.serviceName + ":" + a.value);
}
}
for (BinaryAnnotation b : span.binaryAnnotations) {
if (b.type != BinaryAnnotation.Type.STRING || b.endpoint == null || b.endpoint.serviceName.isEmpty() || b.value.length > LONGEST_VALUE_TO_INDEX * 4) {
// UTF_8 is up to 4bytes/char
continue;
}
String value = new String(b.value, UTF_8);
if (value.length() > LONGEST_VALUE_TO_INDEX)
continue;
annotationKeys.add(b.endpoint.serviceName + ";" + b.key + ";" + new String(b.value, UTF_8));
}
return annotationKeys;
}
use of zipkin.BinaryAnnotation in project zipkin by openzipkin.
the class MySQLSpanConsumer method accept.
/** Blocking version of {@link AsyncSpanConsumer#accept} */
@Override
public void accept(List<Span> spans) {
if (spans.isEmpty())
return;
try (Connection conn = datasource.getConnection()) {
DSLContext create = context.get(conn);
List<Query> inserts = new ArrayList<>();
for (Span span : spans) {
Long overridingTimestamp = authoritativeTimestamp(span);
Long timestamp = overridingTimestamp != null ? overridingTimestamp : guessTimestamp(span);
Map<TableField<Record, ?>, Object> updateFields = new LinkedHashMap<>();
if (!span.name.equals("") && !span.name.equals("unknown")) {
updateFields.put(ZIPKIN_SPANS.NAME, span.name);
}
// replace any tentative timestamp with the authoritative one.
if (overridingTimestamp != null) {
updateFields.put(ZIPKIN_SPANS.START_TS, overridingTimestamp);
}
if (span.duration != null) {
updateFields.put(ZIPKIN_SPANS.DURATION, span.duration);
}
InsertSetMoreStep<Record> insertSpan = create.insertInto(ZIPKIN_SPANS).set(ZIPKIN_SPANS.TRACE_ID, span.traceId).set(ZIPKIN_SPANS.ID, span.id).set(ZIPKIN_SPANS.PARENT_ID, span.parentId).set(ZIPKIN_SPANS.NAME, span.name).set(ZIPKIN_SPANS.DEBUG, span.debug).set(ZIPKIN_SPANS.START_TS, timestamp).set(ZIPKIN_SPANS.DURATION, span.duration);
if (span.traceIdHigh != 0 && schema.hasTraceIdHigh) {
insertSpan.set(ZIPKIN_SPANS.TRACE_ID_HIGH, span.traceIdHigh);
}
inserts.add(updateFields.isEmpty() ? insertSpan.onDuplicateKeyIgnore() : insertSpan.onDuplicateKeyUpdate().set(updateFields));
for (Annotation annotation : span.annotations) {
InsertSetMoreStep<Record> insert = create.insertInto(ZIPKIN_ANNOTATIONS).set(ZIPKIN_ANNOTATIONS.TRACE_ID, span.traceId).set(ZIPKIN_ANNOTATIONS.SPAN_ID, span.id).set(ZIPKIN_ANNOTATIONS.A_KEY, annotation.value).set(ZIPKIN_ANNOTATIONS.A_TYPE, -1).set(ZIPKIN_ANNOTATIONS.A_TIMESTAMP, annotation.timestamp);
if (span.traceIdHigh != 0 && schema.hasTraceIdHigh) {
insert.set(ZIPKIN_ANNOTATIONS.TRACE_ID_HIGH, span.traceIdHigh);
}
if (annotation.endpoint != null) {
insert.set(ZIPKIN_ANNOTATIONS.ENDPOINT_SERVICE_NAME, annotation.endpoint.serviceName);
insert.set(ZIPKIN_ANNOTATIONS.ENDPOINT_IPV4, annotation.endpoint.ipv4);
if (annotation.endpoint.ipv6 != null && schema.hasIpv6) {
insert.set(ZIPKIN_ANNOTATIONS.ENDPOINT_IPV6, annotation.endpoint.ipv6);
}
insert.set(ZIPKIN_ANNOTATIONS.ENDPOINT_PORT, annotation.endpoint.port);
}
inserts.add(insert.onDuplicateKeyIgnore());
}
for (BinaryAnnotation annotation : span.binaryAnnotations) {
InsertSetMoreStep<Record> insert = create.insertInto(ZIPKIN_ANNOTATIONS).set(ZIPKIN_ANNOTATIONS.TRACE_ID, span.traceId).set(ZIPKIN_ANNOTATIONS.SPAN_ID, span.id).set(ZIPKIN_ANNOTATIONS.A_KEY, annotation.key).set(ZIPKIN_ANNOTATIONS.A_VALUE, annotation.value).set(ZIPKIN_ANNOTATIONS.A_TYPE, annotation.type.value).set(ZIPKIN_ANNOTATIONS.A_TIMESTAMP, timestamp);
if (span.traceIdHigh != 0 && schema.hasTraceIdHigh) {
insert.set(ZIPKIN_ANNOTATIONS.TRACE_ID_HIGH, span.traceIdHigh);
}
if (annotation.endpoint != null) {
insert.set(ZIPKIN_ANNOTATIONS.ENDPOINT_SERVICE_NAME, annotation.endpoint.serviceName);
insert.set(ZIPKIN_ANNOTATIONS.ENDPOINT_IPV4, annotation.endpoint.ipv4);
if (annotation.endpoint.ipv6 != null && schema.hasIpv6) {
insert.set(ZIPKIN_ANNOTATIONS.ENDPOINT_IPV6, annotation.endpoint.ipv6);
}
insert.set(ZIPKIN_ANNOTATIONS.ENDPOINT_PORT, annotation.endpoint.port);
}
inserts.add(insert.onDuplicateKeyIgnore());
}
}
create.batch(inserts).execute();
} catch (SQLException e) {
// TODO
throw new RuntimeException(e);
}
}
use of zipkin.BinaryAnnotation in project zipkin by openzipkin.
the class CorrectForClockSkew method adjustTimestamps.
/** If any annotation has an IP with skew associated, adjust accordingly. */
static Span adjustTimestamps(Span span, ClockSkew skew) {
List<Annotation> annotations = null;
Long annotationTimestamp = null;
for (int i = 0, length = span.annotations.size(); i < length; i++) {
Annotation a = span.annotations.get(i);
if (a.endpoint == null)
continue;
if (ipsMatch(skew.endpoint, a.endpoint)) {
if (annotations == null)
annotations = new ArrayList<>(span.annotations);
if (span.timestamp != null && a.timestamp == span.timestamp) {
annotationTimestamp = a.timestamp;
}
annotations.set(i, a.toBuilder().timestamp(a.timestamp - skew.skew).build());
}
}
if (annotations != null) {
Span.Builder builder = span.toBuilder().annotations(annotations);
if (annotationTimestamp != null) {
builder.timestamp(annotationTimestamp - skew.skew);
}
return builder.build();
}
// Search for a local span on the skewed endpoint
for (int i = 0, length = span.binaryAnnotations.size(); i < length; i++) {
BinaryAnnotation b = span.binaryAnnotations.get(i);
if (b.endpoint == null)
continue;
if (b.key.equals(Constants.LOCAL_COMPONENT) && ipsMatch(skew.endpoint, b.endpoint)) {
return span.toBuilder().timestamp(span.timestamp - skew.skew).build();
}
}
return span;
}
use of zipkin.BinaryAnnotation in project zipkin by openzipkin.
the class SpanStoreTest method getTraces_manyTraces.
/**
* Formerly, a bug was present where cassandra didn't index more than bucket count traces per
* millisecond. This stores a lot of spans to ensure indexes work under high-traffic scenarios.
*/
@Test
public void getTraces_manyTraces() {
int traceCount = 1000;
Span span = TestObjects.LOTS_OF_SPANS[0];
BinaryAnnotation b = span.binaryAnnotations.get(0);
accept(Arrays.copyOfRange(TestObjects.LOTS_OF_SPANS, 0, traceCount));
assertThat(store().getTraces(new QueryRequest.Builder().limit(traceCount).build())).hasSize(traceCount);
QueryRequest.Builder builder = QueryRequest.builder().limit(traceCount).serviceName(b.endpoint.serviceName);
assertThat(store().getTraces(builder.build())).hasSize(traceCount);
assertThat(store().getTraces(builder.spanName(span.name).build())).hasSize(traceCount);
assertThat(store().getTraces(builder.addBinaryAnnotation(b.key, new String(b.value)).build())).hasSize(traceCount);
}
Aggregations