Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add is_remote_parent span flags to OTLP exported Spans and SpanLinks #6388

Merged
merged 4 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

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

import io.opentelemetry.api.trace.TraceFlags;

/**
* Represents the 32 bit span flags <a
* href="https://github.com/open-telemetry/opentelemetry-proto/blob/342e1d4c3a1fe43312823ffb53bd38327f263059/opentelemetry/proto/trace/v1/trace.proto#L133">as
* specified in the proto definition</a>.
*/
public final class SpanFlags {
// As defined at:
// https://github.com/open-telemetry/opentelemetry-proto/blob/342e1d4c3a1fe43312823ffb53bd38327f263059/opentelemetry/proto/trace/v1/trace.proto#L351-L352
static final int CONTEXT_HAS_IS_REMOTE_BIT = 0x00000100;
static final int CONTEXT_IS_REMOTE_BIT = 0x00000200;
static final int CONTEXT_IS_REMOTE_MASK = CONTEXT_HAS_IS_REMOTE_BIT | CONTEXT_IS_REMOTE_BIT;

private SpanFlags() {}

/**
* Returns the int (fixed32) representation of the {@link TraceFlags} enriched with the flags
* indicating a remote parent.
*
* @param isParentRemote indicates whether the parent context is remote
* @return the int (fixed32) representation of the {@link TraceFlags} enriched with the flags
* indicating a remote parent.
*/
public static int withParentIsRemoteFlags(TraceFlags traceFlags, boolean isParentRemote) {
byte byteRep = traceFlags.asByte();
if (isParentRemote) {
return (byteRep & 0xff) | CONTEXT_IS_REMOTE_MASK;
}
return (byteRep & 0xff) | CONTEXT_HAS_IS_REMOTE_BIT;
}
breedx-splk marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns the int (fixed32) representation of the 4 bytes flags with the
* has_parent_context_is_remote flag bit on.
*
* @return the int (fixed32) representation of the 4 bytes flags with the *
* has_parent_context_is_remote flag bit on.
*/
public static int getHasParentIsRemoteMask() {
return CONTEXT_HAS_IS_REMOTE_BIT;
}

/**
* Checks whether the given flags contain information about parent context being remote or not.
*
* @param flags The int representation of the 32 bit span flags field defined in proto.
* @return True, if the given flags contain information about the span's parent context being
* remote, otherwise, false.
*/
public static boolean isKnownWhetherParentIsRemote(int flags) {
return (flags & CONTEXT_HAS_IS_REMOTE_BIT) != 0;
}

/**
* Returns the int (fixed32) representation of the 4 bytes flags with the
* has_parent_context_is_remote and parent_context_is_remote flag bits on.
*
* @return the int (fixed32) representation of the 4 bytes flags with the
* has_parent_context_is_remote and parent_context_is_remote flag bits on.
*/
public static int getParentIsRemoteMask() {
return CONTEXT_IS_REMOTE_MASK;
}

/**
* Checks whether in the given flags the parent is marked as remote.
*
* @param flags The int representation of the 32 bit span flags field defined in proto.
* @return True, if the given flags contain information about the span's parent context and the
* parent is marked as remote, otherwise false.
*/
public static boolean isParentRemote(int flags) {
return (flags & CONTEXT_IS_REMOTE_MASK) == CONTEXT_IS_REMOTE_MASK;
}

/**
* Returns the W3C {@link TraceFlags} (least significant 8 bits) portion from the given 32 bit
* span flags fields.
*
* @param flags The int representation of the 32 bit span flags field defined in proto.
* @return the W3C {@link TraceFlags} (least significant 8 bits) portion from the given 32 bit
* span flags fields.
*/
public static TraceFlags getTraceFlags(int flags) {
return TraceFlags.fromByte((byte) (flags & 0xff));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ final class SpanLinkMarshaler extends MarshalerWithSize {
private final KeyValueMarshaler[] attributeMarshalers;
private final int droppedAttributesCount;
private final TraceFlags traceFlags;
private final boolean isLinkContextRemote;

static SpanLinkMarshaler[] createRepeated(List<LinkData> links) {
if (links.isEmpty()) {
Expand All @@ -50,13 +51,15 @@ static SpanLinkMarshaler create(LinkData link) {
traceState.isEmpty()
? EMPTY_BYTES
: encodeTraceState(traceState).getBytes(StandardCharsets.UTF_8);

return new SpanLinkMarshaler(
link.getSpanContext().getTraceId(),
link.getSpanContext().getSpanId(),
link.getSpanContext().getTraceFlags(),
traceStateUtf8,
KeyValueMarshaler.createForAttributes(link.getAttributes()),
link.getTotalAttributeCount() - link.getAttributes().size());
link.getTotalAttributeCount() - link.getAttributes().size(),
link.getSpanContext().isRemote());
}

private SpanLinkMarshaler(
Expand All @@ -65,21 +68,24 @@ private SpanLinkMarshaler(
TraceFlags traceFlags,
byte[] traceStateUtf8,
KeyValueMarshaler[] attributeMarshalers,
int droppedAttributesCount) {
int droppedAttributesCount,
boolean isLinkContextRemote) {
super(
calculateSize(
traceId,
spanId,
traceFlags,
traceStateUtf8,
attributeMarshalers,
droppedAttributesCount));
droppedAttributesCount,
isLinkContextRemote));
this.traceId = traceId;
this.spanId = spanId;
this.traceFlags = traceFlags;
this.traceStateUtf8 = traceStateUtf8;
this.attributeMarshalers = attributeMarshalers;
this.droppedAttributesCount = droppedAttributesCount;
this.isLinkContextRemote = isLinkContextRemote;
}

@Override
Expand All @@ -89,7 +95,8 @@ 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, SpanFlags.withParentIsRemoteFlags(traceFlags, isLinkContextRemote));
}

private static int calculateSize(
Expand All @@ -98,14 +105,17 @@ private static int calculateSize(
TraceFlags flags,
byte[] traceStateUtf8,
KeyValueMarshaler[] attributeMarshalers,
int droppedAttributesCount) {
int droppedAttributesCount,
boolean isLinkContextRemote) {
int size = 0;
size += MarshalerUtil.sizeTraceId(Span.Link.TRACE_ID, traceId);
size += MarshalerUtil.sizeSpanId(Span.Link.SPAN_ID, spanId);
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, SpanFlags.withParentIsRemoteFlags(flags, isLinkContextRemote));
return size;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ final class SpanMarshaler extends MarshalerWithSize {
private final int droppedLinksCount;
private final SpanStatusMarshaler spanStatusMarshaler;
private final TraceFlags flags;
private final boolean isParentContextRemote;

// Because SpanMarshaler is always part of a repeated field, it cannot return "null".
static SpanMarshaler create(SpanData spanData) {
Expand Down Expand Up @@ -75,7 +76,8 @@ static SpanMarshaler create(SpanData spanData) {
spanLinkMarshalers,
spanData.getTotalRecordedLinks() - spanData.getLinks().size(),
SpanStatusMarshaler.create(spanData.getStatus()),
spanData.getSpanContext().getTraceFlags());
spanData.getSpanContext().getTraceFlags(),
spanData.getParentSpanContext().isRemote());
}

private SpanMarshaler(
Expand All @@ -94,7 +96,8 @@ private SpanMarshaler(
SpanLinkMarshaler[] spanLinkMarshalers,
int droppedLinksCount,
SpanStatusMarshaler spanStatusMarshaler,
TraceFlags flags) {
TraceFlags flags,
boolean isParentContextRemote) {
super(
calculateSize(
traceId,
Expand All @@ -112,7 +115,8 @@ private SpanMarshaler(
spanLinkMarshalers,
droppedLinksCount,
spanStatusMarshaler,
flags));
flags,
isParentContextRemote));
this.traceId = traceId;
this.spanId = spanId;
this.traceStateUtf8 = traceStateUtf8;
Expand All @@ -129,6 +133,7 @@ private SpanMarshaler(
this.droppedLinksCount = droppedLinksCount;
this.spanStatusMarshaler = spanStatusMarshaler;
this.flags = flags;
this.isParentContextRemote = isParentContextRemote;
}

@Override
Expand All @@ -154,7 +159,8 @@ 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, SpanFlags.withParentIsRemoteFlags(flags, isParentContextRemote));
}

private static int calculateSize(
Expand All @@ -173,7 +179,8 @@ private static int calculateSize(
SpanLinkMarshaler[] spanLinkMarshalers,
int droppedLinksCount,
SpanStatusMarshaler spanStatusMarshaler,
TraceFlags flags) {
TraceFlags flags,
boolean isParentContextRemote) {
int size = 0;
size += MarshalerUtil.sizeTraceId(Span.TRACE_ID, traceId);
size += MarshalerUtil.sizeSpanId(Span.SPAN_ID, spanId);
Expand All @@ -196,7 +203,9 @@ 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, SpanFlags.withParentIsRemoteFlags(flags, isParentContextRemote));
return size;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

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

import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.api.trace.TraceFlags;
import org.junit.jupiter.api.Test;

/** Unit tests for {@link SpanFlags}. */
public class SpanFlagsTest {

@Test
void withParentIsRemoteFlags() {
assertThat(SpanFlags.withParentIsRemoteFlags(TraceFlags.fromByte((byte) 0xff), false))
.isEqualTo(0x1ff);
assertThat(SpanFlags.withParentIsRemoteFlags(TraceFlags.fromByte((byte) 0x01), false))
.isEqualTo(0x101);
assertThat(SpanFlags.withParentIsRemoteFlags(TraceFlags.fromByte((byte) 0x05), false))
.isEqualTo(0x105);
assertThat(SpanFlags.withParentIsRemoteFlags(TraceFlags.fromByte((byte) 0x00), false))
.isEqualTo(0x100);

assertThat(SpanFlags.withParentIsRemoteFlags(TraceFlags.fromByte((byte) 0xff), true))
.isEqualTo(0x3ff);
assertThat(SpanFlags.withParentIsRemoteFlags(TraceFlags.fromByte((byte) 0x01), true))
.isEqualTo(0x301);
assertThat(SpanFlags.withParentIsRemoteFlags(TraceFlags.fromByte((byte) 0x05), true))
.isEqualTo(0x305);
assertThat(SpanFlags.withParentIsRemoteFlags(TraceFlags.fromByte((byte) 0x00), true))
.isEqualTo(0x300);
}

@Test
void getTraceFlags() {
assertThat(SpanFlags.getTraceFlags(0x1ff)).isEqualTo(TraceFlags.fromByte((byte) 0xff));
assertThat(SpanFlags.getTraceFlags(0xffffffff)).isEqualTo(TraceFlags.fromByte((byte) 0xff));
assertThat(SpanFlags.getTraceFlags(0x000000ff)).isEqualTo(TraceFlags.fromByte((byte) 0xff));

assertThat(SpanFlags.getTraceFlags(0x100)).isEqualTo(TraceFlags.fromByte((byte) 0x00));
assertThat(SpanFlags.getTraceFlags(0xffffff00)).isEqualTo(TraceFlags.fromByte((byte) 0x00));
assertThat(SpanFlags.getTraceFlags(0x00000000)).isEqualTo(TraceFlags.fromByte((byte) 0x00));

assertThat(SpanFlags.getTraceFlags(0x101)).isEqualTo(TraceFlags.fromByte((byte) 0x01));
assertThat(SpanFlags.getTraceFlags(0xffffff01)).isEqualTo(TraceFlags.fromByte((byte) 0x01));
assertThat(SpanFlags.getTraceFlags(0x00000001)).isEqualTo(TraceFlags.fromByte((byte) 0x01));
}

@Test
void isKnownWhetherParentIsRemote() {
assertThat(SpanFlags.isKnownWhetherParentIsRemote(SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT))
.isTrue();
assertThat(
SpanFlags.isKnownWhetherParentIsRemote(
0x00000001 | SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT))
.isTrue();
assertThat(
SpanFlags.isKnownWhetherParentIsRemote(
0x10000000 | SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT))
.isTrue();
assertThat(
SpanFlags.isKnownWhetherParentIsRemote(
0x00000200 | SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT))
.isTrue();
assertThat(SpanFlags.isKnownWhetherParentIsRemote(SpanFlags.CONTEXT_IS_REMOTE_MASK)).isTrue();
assertThat(SpanFlags.isKnownWhetherParentIsRemote(0xffffffff)).isTrue();

assertThat(SpanFlags.isKnownWhetherParentIsRemote(~SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT))
.isFalse();
assertThat(
SpanFlags.isKnownWhetherParentIsRemote(
0x00000001 & ~SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT))
.isFalse();
assertThat(
SpanFlags.isKnownWhetherParentIsRemote(
0x10000000 & ~SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT))
.isFalse();
assertThat(
SpanFlags.isKnownWhetherParentIsRemote(
0x00000200 & ~SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT))
.isFalse();
assertThat(SpanFlags.isKnownWhetherParentIsRemote(0x00000000)).isFalse();
}

@Test
void isParentRemote() {
assertThat(
SpanFlags.isParentRemote(
SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT | SpanFlags.CONTEXT_IS_REMOTE_BIT))
.isTrue();
assertThat(
SpanFlags.isParentRemote(
0x00000001 | SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT | SpanFlags.CONTEXT_IS_REMOTE_BIT))
.isTrue();
assertThat(
SpanFlags.isParentRemote(
0x10000000 | SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT | SpanFlags.CONTEXT_IS_REMOTE_BIT))
.isTrue();
assertThat(
SpanFlags.isParentRemote(
0x00000200 | SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT | SpanFlags.CONTEXT_IS_REMOTE_BIT))
.isTrue();
assertThat(SpanFlags.isParentRemote(SpanFlags.CONTEXT_IS_REMOTE_MASK)).isTrue();
assertThat(SpanFlags.isParentRemote(0xffffffff)).isTrue();

assertThat(SpanFlags.isParentRemote(SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT)).isFalse();
assertThat(SpanFlags.isParentRemote(~SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT)).isFalse();
assertThat(SpanFlags.isParentRemote(SpanFlags.CONTEXT_IS_REMOTE_BIT)).isFalse();
assertThat(SpanFlags.isParentRemote(~SpanFlags.CONTEXT_IS_REMOTE_BIT)).isFalse();
assertThat(
SpanFlags.isParentRemote(
~SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT & ~SpanFlags.CONTEXT_IS_REMOTE_BIT))
.isFalse();
assertThat(SpanFlags.isParentRemote(0x00000200 & ~SpanFlags.CONTEXT_HAS_IS_REMOTE_BIT))
.isFalse();
assertThat(SpanFlags.isParentRemote(0x00000000)).isFalse();
}
}
Loading
Loading