Skip to content

Commit

Permalink
Add dropped attribute/event counts to jaeger and zipkin exporters. (#…
Browse files Browse the repository at this point in the history
…3201)

* Add dropped attribute/event counts to jaeger and zipkin exporters.
Resolves #3197

* Small refactoring from feedback

* formatting
  • Loading branch information
jkwatson authored May 6, 2021
1 parent 6584840 commit 910e66c
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ final class Adapter {
static final AttributeKey<Boolean> KEY_ERROR = booleanKey("error");
static final String KEY_LOG_EVENT = "event";
static final String KEY_EVENT_DROPPED_ATTRIBUTES_COUNT = "otel.event.dropped_attributes_count";
static final String KEY_DROPPED_ATTRIBUTES_COUNT = "otel.dropped_attributes_count";
static final String KEY_DROPPED_EVENTS_COUNT = "otel.dropped_events_count";
static final String KEY_SPAN_KIND = "span.kind";
static final String KEY_SPAN_STATUS_MESSAGE = "otel.status_message";
static final String KEY_SPAN_STATUS_CODE = "otel.status_code";
Expand Down Expand Up @@ -78,8 +80,17 @@ static Span toJaeger(SpanData span) {
TimeUnit.NANOSECONDS.toMicros(span.getEndEpochNanos() - span.getStartEpochNanos()));

List<Tag> tags = toTags(span.getAttributes());
int droppedAttributes = span.getTotalAttributeCount() - span.getAttributes().size();
if (droppedAttributes > 0) {
tags.add(new Tag(KEY_DROPPED_ATTRIBUTES_COUNT, TagType.LONG).setVLong(droppedAttributes));
}

target.setLogs(toJaegerLogs(span.getEvents()));
int droppedEvents = span.getTotalRecordedEvents() - span.getEvents().size();
if (droppedEvents > 0) {
tags.add(new Tag(KEY_DROPPED_EVENTS_COUNT, TagType.LONG).setVLong(droppedEvents));
}

List<SpanRef> references = toSpanRefs(span.getLinks());

// add the parent span
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ void testThriftSpan() {
long startMs = System.currentTimeMillis();
long endMs = startMs + duration;

SpanData span = getSpanData(startMs, endMs, SpanKind.SERVER);
SpanData span = getSpanData(startMs, endMs, SpanKind.SERVER, 2, 4);

// test
io.jaegertracing.thriftjava.Span jaegerSpan = Adapter.toJaeger(span);
Expand All @@ -85,12 +85,16 @@ void testThriftSpan() {
assertThat(jaegerSpan.getStartTime()).isEqualTo(MILLISECONDS.toMicros(startMs));
assertThat(jaegerSpan.getDuration()).isEqualTo(MILLISECONDS.toMicros(duration));

assertThat(jaegerSpan.getTagsSize()).isEqualTo(5);
assertThat(jaegerSpan.getTagsSize()).isEqualTo(7);
assertThat(getValue(jaegerSpan.getTags(), Adapter.KEY_SPAN_KIND).getVStr()).isEqualTo("server");
assertThat(getValue(jaegerSpan.getTags(), Adapter.KEY_SPAN_STATUS_CODE).getVLong())
.isEqualTo(0);
assertThat(getValue(jaegerSpan.getTags(), Adapter.KEY_SPAN_STATUS_MESSAGE).getVStr())
.isEqualTo("ok!");
assertThat(getValue(jaegerSpan.getTags(), Adapter.KEY_DROPPED_EVENTS_COUNT).getVLong())
.isEqualTo(1);
assertThat(getValue(jaegerSpan.getTags(), Adapter.KEY_DROPPED_ATTRIBUTES_COUNT).getVLong())
.isEqualTo(3);

assertThat(jaegerSpan.getLogsSize()).isEqualTo(1);
Log log = jaegerSpan.getLogs().get(0);
Expand Down Expand Up @@ -276,6 +280,11 @@ private static EventData getTimedEvent(int totalAttributeCount) {
}

private static SpanData getSpanData(long startMs, long endMs, SpanKind kind) {
return getSpanData(startMs, endMs, kind, 1, 1);
}

private static SpanData getSpanData(
long startMs, long endMs, SpanKind kind, int totalRecordedEvents, int totalAttributeCount) {
Attributes attributes = Attributes.of(booleanKey("valueB"), true);

LinkData link = LinkData.create(createSpanContext(LINK_TRACE_ID, LINK_SPAN_ID), attributes);
Expand All @@ -290,8 +299,9 @@ private static SpanData getSpanData(long startMs, long endMs, SpanKind kind) {
.setStartEpochNanos(MILLISECONDS.toNanos(startMs))
.setEndEpochNanos(MILLISECONDS.toNanos(endMs))
.setAttributes(Attributes.of(booleanKey("valueB"), true))
.setTotalAttributeCount(totalAttributeCount)
.setEvents(Collections.singletonList(getTimedEvent()))
.setTotalRecordedEvents(1)
.setTotalRecordedEvents(totalRecordedEvents)
.setLinks(Collections.singletonList(link))
.setTotalRecordedLinks(1)
.setKind(kind)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ final class Adapter {
static final AttributeKey<Boolean> KEY_ERROR = booleanKey("error");
static final String KEY_LOG_EVENT = "event";
static final String KEY_EVENT_DROPPED_ATTRIBUTES_COUNT = "otel.event.dropped_attributes_count";
static final String KEY_DROPPED_ATTRIBUTES_COUNT = "otel.dropped_attributes_count";
static final String KEY_DROPPED_EVENTS_COUNT = "otel.dropped_events_count";
static final String KEY_SPAN_KIND = "span.kind";
static final String KEY_SPAN_STATUS_MESSAGE = "otel.status_description";
static final String KEY_SPAN_STATUS_CODE = "otel.status_code";
Expand Down Expand Up @@ -75,7 +77,16 @@ static Model.Span toJaeger(SpanData span) {
Timestamps.between(startTimestamp, Timestamps.fromNanos(span.getEndEpochNanos())));

target.addAllTags(toKeyValues(span.getAttributes()));
int droppedAttributes = span.getTotalAttributeCount() - span.getAttributes().size();
if (droppedAttributes > 0) {
target.addTags(toKeyValue(KEY_DROPPED_ATTRIBUTES_COUNT, droppedAttributes));
}

target.addAllLogs(toJaegerLogs(span.getEvents()));
int droppedEvents = span.getTotalRecordedEvents() - span.getEvents().size();
if (droppedEvents > 0) {
target.addTags(toKeyValue(KEY_DROPPED_EVENTS_COUNT, droppedEvents));
}
target.addAllReferences(toSpanRefs(span.getLinks()));

// add the parent span
Expand All @@ -89,41 +100,26 @@ static Model.Span toJaeger(SpanData span) {
}

if (span.getKind() != SpanKind.INTERNAL) {
target.addTags(
Model.KeyValue.newBuilder()
.setKey(KEY_SPAN_KIND)
.setVStr(span.getKind().name().toLowerCase(Locale.ROOT))
.build());
target.addTags(toKeyValue(KEY_SPAN_KIND, span.getKind().name().toLowerCase(Locale.ROOT)));
}

if (!span.getStatus().getDescription().isEmpty()) {
target.addTags(
Model.KeyValue.newBuilder()
.setKey(KEY_SPAN_STATUS_MESSAGE)
.setVStr(span.getStatus().getDescription())
.build());
target.addTags(toKeyValue(KEY_SPAN_STATUS_MESSAGE, span.getStatus().getDescription()));
}

if (span.getStatus().getStatusCode() != StatusCode.UNSET) {
target.addTags(
Model.KeyValue.newBuilder()
.setKey(KEY_SPAN_STATUS_CODE)
.setVStr(span.getStatus().getStatusCode().name())
.build());
target.addTags(toKeyValue(KEY_SPAN_STATUS_CODE, span.getStatus().getStatusCode().name()));
}

target.addTags(
Model.KeyValue.newBuilder()
.setKey(KEY_INSTRUMENTATION_LIBRARY_NAME)
.setVStr(span.getInstrumentationLibraryInfo().getName())
.build());
toKeyValue(
KEY_INSTRUMENTATION_LIBRARY_NAME, span.getInstrumentationLibraryInfo().getName()));

if (span.getInstrumentationLibraryInfo().getVersion() != null) {
target.addTags(
Model.KeyValue.newBuilder()
.setKey(KEY_INSTRUMENTATION_LIBRARY_VERSION)
.setVStr(span.getInstrumentationLibraryInfo().getVersion())
.build());
toKeyValue(
KEY_INSTRUMENTATION_LIBRARY_VERSION,
span.getInstrumentationLibraryInfo().getVersion()));
}

if (span.getStatus().getStatusCode() == StatusCode.ERROR) {
Expand Down Expand Up @@ -161,8 +157,7 @@ static Model.Log toJaegerLog(EventData event) {
builder.setTimestamp(Timestamps.fromNanos(event.getEpochNanos()));

// name is a top-level property in OpenTelemetry
builder.addFields(
Model.KeyValue.newBuilder().setKey(KEY_LOG_EVENT).setVStr(event.getName()).build());
builder.addFields(toKeyValue(KEY_LOG_EVENT, event.getName()));

int droppedAttributesCount = event.getDroppedAttributesCount();
if (droppedAttributesCount > 0) {
Expand Down Expand Up @@ -231,6 +226,14 @@ static Model.KeyValue toKeyValue(AttributeKey<?> key, Object value) {
return builder.build();
}

private static Model.KeyValue toKeyValue(String key, String value) {
return Model.KeyValue.newBuilder().setKey(key).setVStr(value).build();
}

private static Model.KeyValue toKeyValue(String key, long value) {
return Model.KeyValue.newBuilder().setKey(key).setVInt64(value).build();
}

/**
* Converts {@link LinkData}s into a collection of Jaeger's {@link Model.SpanRef}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void testProtoSpan() {
long startMs = System.currentTimeMillis();
long endMs = startMs + duration;

SpanData span = getSpanData(startMs, endMs, SpanKind.SERVER);
SpanData span = getSpanData(startMs, endMs, SpanKind.SERVER, 2);

// test
Model.Span jaegerSpan = Adapter.toJaeger(span);
Expand All @@ -80,12 +80,30 @@ void testProtoSpan() {
assertThat(jaegerSpan.getStartTime()).isEqualTo(Timestamps.fromMillis(startMs));
assertThat(Durations.toMillis(jaegerSpan.getDuration())).isEqualTo(duration);

assertThat(jaegerSpan.getTagsCount()).isEqualTo(4);
assertThat(jaegerSpan.getTagsCount()).isEqualTo(6);
Model.KeyValue keyValue = getValue(jaegerSpan.getTagsList(), Adapter.KEY_SPAN_KIND);
assertThat(keyValue).isNotNull();
assertThat(keyValue.getVStr()).isEqualTo("server");

Model.KeyValue droppedAttributes =
getValue(jaegerSpan.getTagsList(), Adapter.KEY_DROPPED_ATTRIBUTES_COUNT);
assertThat(droppedAttributes)
.isEqualTo(
Model.KeyValue.newBuilder()
.setKey(Adapter.KEY_DROPPED_ATTRIBUTES_COUNT)
.setVInt64(2)
.build());

assertThat(jaegerSpan.getLogsCount()).isEqualTo(1);
Model.KeyValue droppedEvents =
getValue(jaegerSpan.getTagsList(), Adapter.KEY_DROPPED_EVENTS_COUNT);
assertThat(droppedEvents)
.isEqualTo(
Model.KeyValue.newBuilder()
.setKey(Adapter.KEY_DROPPED_EVENTS_COUNT)
.setVInt64(1)
.build());

Model.Log log = jaegerSpan.getLogs(0);
keyValue = getValue(log.getFieldsList(), Adapter.KEY_LOG_EVENT);
assertThat(keyValue).isNotNull();
Expand Down Expand Up @@ -288,6 +306,11 @@ private static EventData getTimedEvent(int totalAttributeCount) {
}

private static SpanData getSpanData(long startMs, long endMs, SpanKind kind) {
return getSpanData(startMs, endMs, kind, 1);
}

private static SpanData getSpanData(
long startMs, long endMs, SpanKind kind, int totalRecordedEvents) {
Attributes attributes = Attributes.of(booleanKey("valueB"), true);

LinkData link = LinkData.create(createSpanContext(LINK_TRACE_ID, LINK_SPAN_ID), attributes);
Expand All @@ -302,8 +325,9 @@ private static SpanData getSpanData(long startMs, long endMs, SpanKind kind) {
.setStartEpochNanos(TimeUnit.MILLISECONDS.toNanos(startMs))
.setEndEpochNanos(TimeUnit.MILLISECONDS.toNanos(endMs))
.setAttributes(Attributes.of(booleanKey("valueB"), true))
.setTotalAttributeCount(3)
.setEvents(Collections.singletonList(getTimedEvent()))
.setTotalRecordedEvents(1)
.setTotalRecordedEvents(totalRecordedEvents)
.setLinks(Collections.singletonList(link))
.setTotalRecordedLinks(1)
.setKind(kind)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public final class ZipkinSpanExporter implements SpanExporter {

private final ThrottlingLogger logger = new ThrottlingLogger(baseLogger);

static final String OTEL_DROPPED_ATTRIBUTES_COUNT = "otel.dropped_attributes_count";
static final String OTEL_DROPPED_EVENTS_COUNT = "otel.dropped_events_count";
static final String OTEL_STATUS_CODE = "otel.status_code";
static final AttributeKey<String> STATUS_ERROR = stringKey("error");

Expand Down Expand Up @@ -107,6 +109,11 @@ Span generateSpan(SpanData spanData) {
Attributes spanAttributes = spanData.getAttributes();
spanAttributes.forEach(
(key, value) -> spanBuilder.putTag(key.getKey(), valueToString(key, value)));
int droppedAttributes = spanData.getTotalAttributeCount() - spanAttributes.size();
if (droppedAttributes > 0) {
spanBuilder.putTag(OTEL_DROPPED_ATTRIBUTES_COUNT, String.valueOf(droppedAttributes));
}

StatusData status = spanData.getStatus();

// include status code & error.
Expand All @@ -133,6 +140,10 @@ Span generateSpan(SpanData spanData) {
for (EventData annotation : spanData.getEvents()) {
spanBuilder.addAnnotation(toEpochMicros(annotation.getEpochNanos()), annotation.getName());
}
int droppedEvents = spanData.getTotalRecordedEvents() - spanData.getEvents().size();
if (droppedEvents > 0) {
spanBuilder.putTag(OTEL_DROPPED_EVENTS_COUNT, String.valueOf(droppedEvents));
}

return spanBuilder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ private static TestSpanData.Builder buildStandardSpan() {
.setStartEpochNanos(START_EPOCH_NANOS)
.setAttributes(attributes)
.setTotalAttributeCount(attributes.size())
.setTotalRecordedEvents(annotations.size())
.setEvents(annotations)
.setLinks(Collections.emptyList())
.setEndEpochNanos(END_EPOCH_NANOS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,13 @@ void generateSpan_WithAttributes() {
.put(doubleArrayKey("doubleArray"), Arrays.asList(32.33d, -98.3d))
.put(longArrayKey("longArray"), Arrays.asList(33L, 999L))
.build();
SpanData data = buildStandardSpan().setAttributes(attributes).setKind(SpanKind.CLIENT).build();
SpanData data =
buildStandardSpan()
.setAttributes(attributes)
.setTotalAttributeCount(28)
.setTotalRecordedEvents(3)
.setKind(SpanKind.CLIENT)
.build();

assertThat(exporter.generateSpan(data))
.isEqualTo(
Expand All @@ -215,6 +221,8 @@ void generateSpan_WithAttributes() {
.putTag("doubleArray", "32.33,-98.3")
.putTag("longArray", "33,999")
.putTag(ZipkinSpanExporter.OTEL_STATUS_CODE, "OK")
.putTag(ZipkinSpanExporter.OTEL_DROPPED_ATTRIBUTES_COUNT, "20")
.putTag(ZipkinSpanExporter.OTEL_DROPPED_EVENTS_COUNT, "1")
.build());
}

Expand Down Expand Up @@ -246,6 +254,7 @@ void generateSpan_AlreadyHasHttpStatusInfo() {
.setAttributes(attributeMap)
.setKind(SpanKind.CLIENT)
.setStatus(StatusData.error())
.setTotalAttributeCount(2)
.build();

assertThat(exporter.generateSpan(data))
Expand All @@ -268,6 +277,7 @@ void generateSpan_WithRpcTimeoutErrorStatus_WithTimeoutErrorDescription() {
buildStandardSpan()
.setStatus(StatusData.create(StatusCode.ERROR, errorMessage))
.setAttributes(attributeMap)
.setTotalAttributeCount(1)
.build();

assertThat(exporter.generateSpan(data))
Expand All @@ -287,6 +297,7 @@ void generateSpan_WithRpcErrorStatus_WithEmptyErrorDescription() {
buildStandardSpan()
.setStatus(StatusData.create(StatusCode.ERROR, ""))
.setAttributes(attributeMap)
.setTotalAttributeCount(1)
.build();

assertThat(exporter.generateSpan(data))
Expand All @@ -306,6 +317,7 @@ void generateSpan_WithRpcUnsetStatus() {
buildStandardSpan()
.setStatus(StatusData.create(StatusCode.UNSET, ""))
.setAttributes(attributeMap)
.setTotalAttributeCount(1)
.build();

assertThat(exporter.generateSpan(data))
Expand Down Expand Up @@ -399,6 +411,7 @@ private static TestSpanData.Builder buildStandardSpan() {
.setEndEpochNanos(1505855799_465726528L)
.setAttributes(attributes)
.setTotalAttributeCount(attributes.size())
.setTotalRecordedEvents(annotations.size())
.setEvents(annotations)
.setLinks(Collections.emptyList())
.setHasEnded(true);
Expand Down

0 comments on commit 910e66c

Please sign in to comment.