use of zipkin2.Span.Kind in project zipkin by openzipkin.
the class BulkIndexWriter method write.
/**
* In order to allow systems like Kibana to search by timestamp, we add a field "timestamp_millis"
* when storing. The cheapest way to do this without changing the codec is prefixing it to the
* json. For example. {"traceId":"... becomes {"timestamp_millis":12345,"traceId":"...
*
* <p>Tags are stored as a dictionary. Since some tag names will include inconsistent number of
* dots (ex "error" and perhaps "error.message"), we cannot index them naturally with
* elasticsearch. Instead, we add an index-only (non-source) field of {@code _q} which includes
* valid search queries. For example, the tag {@code error -> 500} results in {@code
* "_q":["error", "error=500"]}. This matches the input query syntax, and can be checked manually
* with curl.
*
* <p>Ex {@code curl -s localhost:9200/zipkin:span-2017-08-11/_search?q=_q:error=500}
*
* @param searchEnabled encodes timestamp_millis and _q when non-empty
*/
static String write(Span span, boolean searchEnabled, ByteBufOutputStream sink) {
int startIndex = sink.buffer().writerIndex();
try (JsonGenerator writer = JsonSerializers.jsonGenerator(sink)) {
writer.writeStartObject();
if (searchEnabled)
addSearchFields(span, writer);
writer.writeStringField("traceId", span.traceId());
if (span.parentId() != null)
writer.writeStringField("parentId", span.parentId());
writer.writeStringField("id", span.id());
if (span.kind() != null)
writer.writeStringField("kind", span.kind().toString());
if (span.name() != null)
writer.writeStringField("name", span.name());
if (span.timestampAsLong() != 0L) {
writer.writeNumberField("timestamp", span.timestampAsLong());
}
if (span.durationAsLong() != 0L)
writer.writeNumberField("duration", span.durationAsLong());
if (span.localEndpoint() != null && !EMPTY_ENDPOINT.equals(span.localEndpoint())) {
writer.writeFieldName("localEndpoint");
write(span.localEndpoint(), writer);
}
if (span.remoteEndpoint() != null && !EMPTY_ENDPOINT.equals(span.remoteEndpoint())) {
writer.writeFieldName("remoteEndpoint");
write(span.remoteEndpoint(), writer);
}
if (!span.annotations().isEmpty()) {
writer.writeArrayFieldStart("annotations");
for (int i = 0, length = span.annotations().size(); i < length; ) {
write(span.annotations().get(i++), writer);
}
writer.writeEndArray();
}
if (!span.tags().isEmpty()) {
writer.writeObjectFieldStart("tags");
Iterator<Map.Entry<String, String>> tags = span.tags().entrySet().iterator();
while (tags.hasNext()) write(tags.next(), writer);
writer.writeEndObject();
}
if (Boolean.TRUE.equals(span.debug()))
writer.writeBooleanField("debug", true);
if (Boolean.TRUE.equals(span.shared()))
writer.writeBooleanField("shared", true);
writer.writeEndObject();
} catch (IOException e) {
// No I/O writing to a Buffer.
throw new AssertionError(e);
}
// get a slice representing the document we just wrote so that we can make a content hash
ByteBuf slice = sink.buffer().slice(startIndex, sink.buffer().writerIndex() - startIndex);
return span.traceId() + '-' + md5(slice);
}
use of zipkin2.Span.Kind in project zipkin by openzipkin.
the class V2SpanWriter method write.
@Override
public void write(Span value, WriteBuffer b) {
b.writeAscii("{\"traceId\":\"");
b.writeAscii(value.traceId());
b.writeByte('"');
if (value.parentId() != null) {
b.writeAscii(",\"parentId\":\"");
b.writeAscii(value.parentId());
b.writeByte('"');
}
b.writeAscii(",\"id\":\"");
b.writeAscii(value.id());
b.writeByte('"');
if (value.kind() != null) {
b.writeAscii(",\"kind\":\"");
b.writeAscii(value.kind().toString());
b.writeByte('"');
}
if (value.name() != null) {
b.writeAscii(",\"name\":\"");
b.writeUtf8(jsonEscape(value.name()));
b.writeByte('"');
}
if (value.timestampAsLong() != 0L) {
b.writeAscii(",\"timestamp\":");
b.writeAscii(value.timestampAsLong());
}
if (value.durationAsLong() != 0L) {
b.writeAscii(",\"duration\":");
b.writeAscii(value.durationAsLong());
}
if (value.localEndpoint() != null) {
b.writeAscii(",\"localEndpoint\":");
writeEndpoint(value.localEndpoint(), b, false);
}
if (value.remoteEndpoint() != null) {
b.writeAscii(",\"remoteEndpoint\":");
writeEndpoint(value.remoteEndpoint(), b, false);
}
if (!value.annotations().isEmpty()) {
b.writeAscii(",\"annotations\":");
b.writeByte('[');
for (int i = 0, length = value.annotations().size(); i < length; ) {
Annotation a = value.annotations().get(i++);
writeAnnotation(a.timestamp(), a.value(), null, b);
if (i < length)
b.writeByte(',');
}
b.writeByte(']');
}
if (!value.tags().isEmpty()) {
b.writeAscii(",\"tags\":{");
Iterator<Map.Entry<String, String>> i = value.tags().entrySet().iterator();
while (i.hasNext()) {
Map.Entry<String, String> entry = i.next();
b.writeByte('"');
b.writeUtf8(jsonEscape(entry.getKey()));
b.writeAscii("\":\"");
b.writeUtf8(jsonEscape(entry.getValue()));
b.writeByte('"');
if (i.hasNext())
b.writeByte(',');
}
b.writeByte('}');
}
if (Boolean.TRUE.equals(value.debug())) {
b.writeAscii(",\"debug\":true");
}
if (Boolean.TRUE.equals(value.shared())) {
b.writeAscii(",\"shared\":true");
}
b.writeByte('}');
}
use of zipkin2.Span.Kind 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 in project zipkin by openzipkin.
the class SpanConverterTest method producerAndConsumer_loopback_shared.
/**
* shared v1 IDs for messaging spans isn't supported, but shouldn't break
*/
@Test
public void producerAndConsumer_loopback_shared() {
V1Span v1 = V1Span.newBuilder().traceId(1).parentId(2).id(3).name("message").addAnnotation(1472470996199000L, "ms", FRONTEND).addAnnotation(1472470996238000L, "ws", FRONTEND).addAnnotation(1472470996403000L, "wr", FRONTEND).addAnnotation(1472470996406000L, "mr", FRONTEND).build();
Span.Builder newBuilder = Span.newBuilder().traceId("1").parentId("2").id("3").name("message");
Span producer = newBuilder.clone().kind(Kind.PRODUCER).localEndpoint(FRONTEND).timestamp(1472470996199000L).duration(1472470996238000L - 1472470996199000L).build();
Span consumer = newBuilder.clone().kind(Kind.CONSUMER).shared(true).localEndpoint(FRONTEND).timestamp(1472470996403000L).duration(1472470996406000L - 1472470996403000L).build();
assertThat(v1SpanConverter.convert(v1)).containsExactly(producer, consumer);
}
use of zipkin2.Span.Kind in project zipkin by openzipkin.
the class SpanConverterTest method lateRemoteEndpoint_cr.
@Test
public void lateRemoteEndpoint_cr() {
Span v2 = Span.newBuilder().traceId("1").parentId("2").id("3").name("get").kind(Kind.CLIENT).localEndpoint(FRONTEND).remoteEndpoint(BACKEND).addAnnotation(1472470996199000L, "cr").build();
V1Span v1 = V1Span.newBuilder().traceId(1L).parentId(2L).id(3L).name("get").addAnnotation(1472470996199000L, "cr", FRONTEND).addBinaryAnnotation("sa", BACKEND).build();
assertThat(v2SpanConverter.convert(v2)).usingRecursiveComparison().isEqualTo(v1);
assertThat(v1SpanConverter.convert(v1)).containsExactly(v2);
}
Aggregations