From e79e3ee02eeee91a16a927c013e700539da66ce6 Mon Sep 17 00:00:00 2001 From: Alexander Wert Date: Fri, 12 Apr 2024 10:24:26 +0200 Subject: [PATCH] Add is_remote_parent span flags to OTLP exported Spans and SpanLinks Signed-off-by: Alexander Wert --- .../otlp/traces/ProtoSpanFlagsUtil.java | 27 +++++++++++ .../otlp/traces/SpanLinkMarshaler.java | 17 ++++--- .../internal/otlp/traces/SpanMarshaler.java | 17 ++++--- .../traces/TraceRequestMarshalerTest.java | 48 ++++++++++++++++++- 4 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ProtoSpanFlagsUtil.java diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ProtoSpanFlagsUtil.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ProtoSpanFlagsUtil.java new file mode 100644 index 00000000000..2e85bc7a242 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/ProtoSpanFlagsUtil.java @@ -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; + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java index 6adcac370e1..1df71b12b3c 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanLinkMarshaler.java @@ -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; @@ -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 links) { if (links.isEmpty()) { @@ -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()); @@ -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) { @@ -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) { @@ -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; } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java index e2e83c0f129..6660b55357d 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanMarshaler.java @@ -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; @@ -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) { @@ -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(), @@ -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( @@ -94,7 +97,7 @@ private SpanMarshaler( SpanLinkMarshaler[] spanLinkMarshalers, int droppedLinksCount, SpanStatusMarshaler spanStatusMarshaler, - TraceFlags flags) { + int flags) { super( calculateSize( traceId, @@ -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( @@ -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); @@ -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; } diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/TraceRequestMarshalerTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/TraceRequestMarshalerTest.java index 6bc17a22109..b22e81e2904 100644 --- a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/TraceRequestMarshalerTest.java +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/traces/TraceRequestMarshalerTest.java @@ -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( @@ -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 = @@ -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"); @@ -227,7 +235,9 @@ 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 @@ -235,6 +245,40 @@ void toProtoSpan() { .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))