Skip to content

Commit

Permalink
Add is_remote_parent span flags to OTLP exported Spans and SpanLinks
Browse files Browse the repository at this point in the history
Signed-off-by: Alexander Wert <alexander.wert@elastic.co>
  • Loading branch information
AlexanderWert committed Apr 15, 2024
1 parent 8937a10 commit e79e3ee
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.internal.otlp.traces;

import io.opentelemetry.api.trace.SpanContext;

public final class ProtoSpanFlagsUtil {

private ProtoSpanFlagsUtil() {}

public static final int SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK = 0x00000100;
public static final int SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK = 0x00000200;

static int getFullSpanFlags(byte w3cTraceflags, SpanContext parentContext) {
int flags = w3cTraceflags;

flags = flags | SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK;
if (parentContext.isRemote()) {
flags = flags | SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK;
}

return flags;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import static io.opentelemetry.api.trace.propagation.internal.W3CTraceContextEncoding.encodeTraceState;

import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
Expand All @@ -27,7 +26,7 @@ final class SpanLinkMarshaler extends MarshalerWithSize {
private final byte[] traceStateUtf8;
private final KeyValueMarshaler[] attributeMarshalers;
private final int droppedAttributesCount;
private final TraceFlags traceFlags;
private final int traceFlags;

static SpanLinkMarshaler[] createRepeated(List<LinkData> links) {
if (links.isEmpty()) {
Expand All @@ -50,10 +49,14 @@ static SpanLinkMarshaler create(LinkData link) {
traceState.isEmpty()
? EMPTY_BYTES
: encodeTraceState(traceState).getBytes(StandardCharsets.UTF_8);
int flags =
ProtoSpanFlagsUtil.getFullSpanFlags(
link.getSpanContext().getTraceFlags().asByte(), link.getSpanContext());

return new SpanLinkMarshaler(
link.getSpanContext().getTraceId(),
link.getSpanContext().getSpanId(),
link.getSpanContext().getTraceFlags(),
flags,
traceStateUtf8,
KeyValueMarshaler.createForAttributes(link.getAttributes()),
link.getTotalAttributeCount() - link.getAttributes().size());
Expand All @@ -62,7 +65,7 @@ static SpanLinkMarshaler create(LinkData link) {
private SpanLinkMarshaler(
String traceId,
String spanId,
TraceFlags traceFlags,
int traceFlags,
byte[] traceStateUtf8,
KeyValueMarshaler[] attributeMarshalers,
int droppedAttributesCount) {
Expand All @@ -89,13 +92,13 @@ public void writeTo(Serializer output) throws IOException {
output.serializeString(Span.Link.TRACE_STATE, traceStateUtf8);
output.serializeRepeatedMessage(Span.Link.ATTRIBUTES, attributeMarshalers);
output.serializeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount);
output.serializeByteAsFixed32(Span.Link.FLAGS, traceFlags.asByte());
output.serializeFixed32(Span.Link.FLAGS, traceFlags);
}

private static int calculateSize(
String traceId,
String spanId,
TraceFlags flags,
int flags,
byte[] traceStateUtf8,
KeyValueMarshaler[] attributeMarshalers,
int droppedAttributesCount) {
Expand All @@ -105,7 +108,7 @@ private static int calculateSize(
size += MarshalerUtil.sizeBytes(Span.Link.TRACE_STATE, traceStateUtf8);
size += MarshalerUtil.sizeRepeatedMessage(Span.Link.ATTRIBUTES, attributeMarshalers);
size += MarshalerUtil.sizeUInt32(Span.Link.DROPPED_ATTRIBUTES_COUNT, droppedAttributesCount);
size += MarshalerUtil.sizeByteAsFixed32(Span.Link.FLAGS, flags.asByte());
size += MarshalerUtil.sizeFixed32(Span.Link.FLAGS, flags);
return size;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import static io.opentelemetry.api.trace.propagation.internal.W3CTraceContextEncoding.encodeTraceState;

import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.exporter.internal.marshal.MarshalerUtil;
import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize;
Expand Down Expand Up @@ -38,7 +37,7 @@ final class SpanMarshaler extends MarshalerWithSize {
private final SpanLinkMarshaler[] spanLinkMarshalers;
private final int droppedLinksCount;
private final SpanStatusMarshaler spanStatusMarshaler;
private final TraceFlags flags;
private final int flags;

// Because SpanMarshaler is always part of a repeated field, it cannot return "null".
static SpanMarshaler create(SpanData spanData) {
Expand All @@ -59,6 +58,10 @@ static SpanMarshaler create(SpanData spanData) {
? EMPTY_BYTES
: encodeTraceState(traceState).getBytes(StandardCharsets.UTF_8);

int flags =
ProtoSpanFlagsUtil.getFullSpanFlags(
spanData.getSpanContext().getTraceFlags().asByte(), spanData.getParentSpanContext());

return new SpanMarshaler(
spanData.getSpanContext().getTraceId(),
spanData.getSpanContext().getSpanId(),
Expand All @@ -75,7 +78,7 @@ static SpanMarshaler create(SpanData spanData) {
spanLinkMarshalers,
spanData.getTotalRecordedLinks() - spanData.getLinks().size(),
SpanStatusMarshaler.create(spanData.getStatus()),
spanData.getSpanContext().getTraceFlags());
flags);
}

private SpanMarshaler(
Expand All @@ -94,7 +97,7 @@ private SpanMarshaler(
SpanLinkMarshaler[] spanLinkMarshalers,
int droppedLinksCount,
SpanStatusMarshaler spanStatusMarshaler,
TraceFlags flags) {
int flags) {
super(
calculateSize(
traceId,
Expand Down Expand Up @@ -154,7 +157,7 @@ public void writeTo(Serializer output) throws IOException {
output.serializeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount);

output.serializeMessage(Span.STATUS, spanStatusMarshaler);
output.serializeByteAsFixed32(Span.FLAGS, flags.asByte());
output.serializeFixed32(Span.FLAGS, flags);
}

private static int calculateSize(
Expand All @@ -173,7 +176,7 @@ private static int calculateSize(
SpanLinkMarshaler[] spanLinkMarshalers,
int droppedLinksCount,
SpanStatusMarshaler spanStatusMarshaler,
TraceFlags flags) {
int flags) {
int size = 0;
size += MarshalerUtil.sizeTraceId(Span.TRACE_ID, traceId);
size += MarshalerUtil.sizeSpanId(Span.SPAN_ID, spanId);
Expand All @@ -196,7 +199,7 @@ private static int calculateSize(
size += MarshalerUtil.sizeUInt32(Span.DROPPED_LINKS_COUNT, droppedLinksCount);

size += MarshalerUtil.sizeMessage(Span.STATUS, spanStatusMarshaler);
size += MarshalerUtil.sizeByteAsFixed32(Span.FLAGS, flags.asByte());
size += MarshalerUtil.sizeFixed32(Span.FLAGS, flags);
return size;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ class TraceRequestMarshalerTest {
new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4};
private static final String TRACE_ID = TraceId.fromBytes(TRACE_ID_BYTES);
private static final byte[] SPAN_ID_BYTES = new byte[] {0, 0, 0, 0, 4, 3, 2, 1};
private static final byte[] PARENT_SPAN_ID_BYTES = new byte[] {0, 0, 0, 0, 5, 6, 7, 8};
private static final String SPAN_ID = SpanId.fromBytes(SPAN_ID_BYTES);
private static final String PARENT_SPAN_ID = SpanId.fromBytes(PARENT_SPAN_ID_BYTES);
private static final String TRACE_STATE_VALUE = "baz=qux,foo=bar";
private static final SpanContext SPAN_CONTEXT =
SpanContext.create(
Expand All @@ -65,6 +67,10 @@ class TraceRequestMarshalerTest {
TraceFlags.getSampled(),
TraceState.builder().put("foo", "bar").put("baz", "qux").build());

private static final SpanContext PARENT_SPAN_CONTEXT =
SpanContext.createFromRemoteParent(
TRACE_ID, PARENT_SPAN_ID, TraceFlags.getSampled(), TraceState.builder().build());

@Test
void toProtoResourceSpans() {
ResourceSpansMarshaler[] resourceSpansMarshalers =
Expand Down Expand Up @@ -148,7 +154,9 @@ void toProtoSpan() {
assertThat(protoSpan.getTraceId().toByteArray()).isEqualTo(TRACE_ID_BYTES);
assertThat(protoSpan.getSpanId().toByteArray()).isEqualTo(SPAN_ID_BYTES);
assertThat(protoSpan.getFlags())
.isEqualTo(((int) SPAN_CONTEXT.getTraceFlags().asByte()) & 0x00ff);
.isEqualTo(
(((int) SPAN_CONTEXT.getTraceFlags().asByte()) & 0x00ff)
| ProtoSpanFlagsUtil.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK);
assertThat(protoSpan.getTraceState()).isEqualTo(TRACE_STATE_VALUE);
assertThat(protoSpan.getParentSpanId().toByteArray()).isEqualTo(new byte[] {});
assertThat(protoSpan.getName()).isEqualTo("GET /api/endpoint");
Expand Down Expand Up @@ -227,14 +235,50 @@ void toProtoSpan() {
Span.Link.newBuilder()
.setTraceId(ByteString.copyFrom(TRACE_ID_BYTES))
.setSpanId(ByteString.copyFrom(SPAN_ID_BYTES))
.setFlags(SPAN_CONTEXT.getTraceFlags().asByte())
.setFlags(
SPAN_CONTEXT.getTraceFlags().asByte()
| ProtoSpanFlagsUtil.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK)
.setTraceState(encodeTraceState(SPAN_CONTEXT.getTraceState()))
.build());
assertThat(protoSpan.getDroppedLinksCount()).isEqualTo(1); // 2 - 1
assertThat(protoSpan.getStatus())
.isEqualTo(Status.newBuilder().setCode(STATUS_CODE_OK).build());
}

@Test
void toProtoSpan_withRemoteParent() {
Span protoSpan =
parse(
Span.getDefaultInstance(),
SpanMarshaler.create(
TestSpanData.builder()
.setHasEnded(true)
.setSpanContext(SPAN_CONTEXT)
.setParentSpanContext(PARENT_SPAN_CONTEXT)
.setName("GET /api/endpoint")
.setKind(SpanKind.SERVER)
.setStartEpochNanos(12345)
.setEndEpochNanos(12349)
.setStatus(StatusData.ok())
.build()));

assertThat(protoSpan.getTraceId().toByteArray()).isEqualTo(TRACE_ID_BYTES);
assertThat(protoSpan.getSpanId().toByteArray()).isEqualTo(SPAN_ID_BYTES);
assertThat(protoSpan.getFlags())
.isEqualTo(
(((int) SPAN_CONTEXT.getTraceFlags().asByte()) & 0x00ff)
| ProtoSpanFlagsUtil.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK
| ProtoSpanFlagsUtil.SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK);
assertThat(protoSpan.getTraceState()).isEqualTo(TRACE_STATE_VALUE);
assertThat(protoSpan.getParentSpanId().toByteArray()).isEqualTo(PARENT_SPAN_ID_BYTES);
assertThat(protoSpan.getName()).isEqualTo("GET /api/endpoint");
assertThat(protoSpan.getKind()).isEqualTo(SPAN_KIND_SERVER);
assertThat(protoSpan.getStartTimeUnixNano()).isEqualTo(12345);
assertThat(protoSpan.getEndTimeUnixNano()).isEqualTo(12349);
assertThat(protoSpan.getStatus())
.isEqualTo(Status.newBuilder().setCode(STATUS_CODE_OK).build());
}

@Test
void toProtoSpanKind() {
assertThat(SpanMarshaler.toProtoSpanKind(SpanKind.INTERNAL))
Expand Down

0 comments on commit e79e3ee

Please sign in to comment.