Skip to content

Commit efe97bf

Browse files
[otlp] Implement Span and SpanLink flags (#5563)
Co-authored-by: Mikel Blanchard <[email protected]>
1 parent 4a1601b commit efe97bf

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
to `OTel-OTLP-Exporter-Dotnet/{NuGet Package Version}`.
88
([#5528](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5528))
99

10+
* Implementation of [OTLP
11+
specification](https://github.com/open-telemetry/opentelemetry-proto/blob/v1.2.0/opentelemetry/proto/trace/v1/trace.proto#L112-L133)
12+
for propagating `Span` and `SpanLink` flags containing W3C trace flags and
13+
`parent_is_remote` information.
14+
([#5563](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5563))
15+
1016
## 1.8.1
1117

1218
Released 2024-Apr-17

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs

+19
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ internal static Span ToOtlpSpan(this Activity activity, SdkLimitOptions sdkLimit
174174
};
175175
otlpLinks.EnumerateLinks(activity, sdkLimitOptions.SpanLinkCountLimit ?? int.MaxValue);
176176

177+
otlpSpan.Flags = ToOtlpSpanFlags(activity.Context.TraceFlags, activity.HasRemoteParent);
178+
177179
return otlpSpan;
178180
}
179181

@@ -250,6 +252,8 @@ private static Span.Types.Link ToOtlpLink(in ActivityLink activityLink, SdkLimit
250252
}
251253
}
252254

255+
otlpLink.Flags = ToOtlpSpanFlags(activityLink.Context.TraceFlags, activityLink.Context.IsRemote);
256+
253257
return otlpLink;
254258
}
255259

@@ -281,6 +285,21 @@ private static Span.Types.Event ToOtlpEvent(in ActivityEvent activityEvent, SdkL
281285
return otlpEvent;
282286
}
283287

288+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
289+
private static uint ToOtlpSpanFlags(ActivityTraceFlags activityTraceFlags, bool isRemote)
290+
{
291+
SpanFlags flags = (SpanFlags)activityTraceFlags;
292+
293+
flags |= SpanFlags.ContextHasIsRemoteMask;
294+
295+
if (isRemote)
296+
{
297+
flags |= SpanFlags.ContextIsRemoteMask;
298+
}
299+
300+
return (uint)flags;
301+
}
302+
284303
private struct TagEnumerationState : PeerServiceResolver.IPeerServiceState
285304
{
286305
public SdkLimitOptions SdkLimitOptions;

test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs

+99
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,10 @@ public void ToOtlpSpanTest()
401401
{
402402
OtlpTestHelpers.AssertOtlpAttributes(childLinks[i].Tags.ToList(), otlpSpan.Links[i].Attributes);
403403
}
404+
405+
var flags = (OtlpTrace.SpanFlags)otlpSpan.Flags;
406+
Assert.True(flags.HasFlag(OtlpTrace.SpanFlags.ContextHasIsRemoteMask));
407+
Assert.False(flags.HasFlag(OtlpTrace.SpanFlags.ContextIsRemoteMask));
404408
}
405409

406410
[Fact]
@@ -731,4 +735,99 @@ public void NamedOptionsMutateSeparateInstancesTest()
731735
Assert.Equal("http://localhost/traces", tracerOptions.Endpoint.OriginalString);
732736
Assert.Equal("http://localhost/metrics", meterOptions.Endpoint.OriginalString);
733737
}
738+
739+
[Theory]
740+
[InlineData(true, true)]
741+
[InlineData(true, false)]
742+
[InlineData(false, true)]
743+
[InlineData(false, false)]
744+
public void SpanFlagsTest(bool isRecorded, bool isRemote)
745+
{
746+
using var activitySource = new ActivitySource(nameof(this.SpanFlagsTest));
747+
748+
ActivityContext ctx = new ActivityContext(
749+
ActivityTraceId.CreateRandom(),
750+
ActivitySpanId.CreateRandom(),
751+
isRecorded ? ActivityTraceFlags.Recorded : ActivityTraceFlags.None,
752+
isRemote: isRemote);
753+
754+
using var rootActivity = activitySource.StartActivity("root", ActivityKind.Server, ctx);
755+
756+
var otlpSpan = rootActivity.ToOtlpSpan(DefaultSdkLimitOptions);
757+
758+
var flags = (OtlpTrace.SpanFlags)otlpSpan.Flags;
759+
760+
ActivityTraceFlags traceFlags = (ActivityTraceFlags)(flags & OtlpTrace.SpanFlags.TraceFlagsMask);
761+
762+
if (isRecorded)
763+
{
764+
Assert.True(traceFlags.HasFlag(ActivityTraceFlags.Recorded));
765+
}
766+
else
767+
{
768+
Assert.False(traceFlags.HasFlag(ActivityTraceFlags.Recorded));
769+
}
770+
771+
Assert.True(flags.HasFlag(OtlpTrace.SpanFlags.ContextHasIsRemoteMask));
772+
773+
if (isRemote)
774+
{
775+
Assert.True(flags.HasFlag(OtlpTrace.SpanFlags.ContextIsRemoteMask));
776+
}
777+
else
778+
{
779+
Assert.False(flags.HasFlag(OtlpTrace.SpanFlags.ContextIsRemoteMask));
780+
}
781+
}
782+
783+
[Theory]
784+
[InlineData(true, true)]
785+
[InlineData(true, false)]
786+
[InlineData(false, true)]
787+
[InlineData(false, false)]
788+
public void SpanLinkFlagsTest(bool isRecorded, bool isRemote)
789+
{
790+
using var activitySource = new ActivitySource(nameof(this.SpanLinkFlagsTest));
791+
792+
ActivityContext ctx = new ActivityContext(
793+
ActivityTraceId.CreateRandom(),
794+
ActivitySpanId.CreateRandom(),
795+
isRecorded ? ActivityTraceFlags.Recorded : ActivityTraceFlags.None,
796+
isRemote: isRemote);
797+
798+
var links = new[]
799+
{
800+
new ActivityLink(ctx),
801+
};
802+
803+
using var rootActivity = activitySource.StartActivity("root", ActivityKind.Server, default(ActivityContext), links: links);
804+
805+
var otlpSpan = rootActivity.ToOtlpSpan(DefaultSdkLimitOptions);
806+
807+
var spanLink = Assert.Single(otlpSpan.Links);
808+
809+
var flags = (OtlpTrace.SpanFlags)spanLink.Flags;
810+
811+
ActivityTraceFlags traceFlags = (ActivityTraceFlags)(flags & OtlpTrace.SpanFlags.TraceFlagsMask);
812+
813+
if (isRecorded)
814+
{
815+
Assert.True(traceFlags.HasFlag(ActivityTraceFlags.Recorded));
816+
}
817+
else
818+
{
819+
Assert.False(traceFlags.HasFlag(ActivityTraceFlags.Recorded));
820+
}
821+
822+
Assert.True(flags.HasFlag(OtlpTrace.SpanFlags.ContextHasIsRemoteMask));
823+
824+
if (isRemote)
825+
{
826+
Assert.True(flags.HasFlag(OtlpTrace.SpanFlags.ContextIsRemoteMask));
827+
}
828+
else
829+
{
830+
Assert.False(flags.HasFlag(OtlpTrace.SpanFlags.ContextIsRemoteMask));
831+
}
832+
}
734833
}

0 commit comments

Comments
 (0)