diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md
index 0345f63aa1c..619ad543626 100644
--- a/src/OpenTelemetry.Api/CHANGELOG.md
+++ b/src/OpenTelemetry.Api/CHANGELOG.md
@@ -2,6 +2,10 @@
## Unreleased
+* Fixed a bug which caused `Tracer.StartRootSpan` to generate a child span if a
+ trace was running (`Activity.Current != null`).
+ ([#4890](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4890))
+
## 1.6.0
Released 2023-Sep-05
diff --git a/src/OpenTelemetry.Api/Trace/Tracer.cs b/src/OpenTelemetry.Api/Trace/Tracer.cs
index a7a0e2ba34e..af626aafc8b 100644
--- a/src/OpenTelemetry.Api/Trace/Tracer.cs
+++ b/src/OpenTelemetry.Api/Trace/Tracer.cs
@@ -35,6 +35,14 @@ internal Tracer(ActivitySource activitySource)
this.ActivitySource = activitySource;
}
+ [Flags]
+ private enum StartSpanBehaviors
+ {
+ ActivateNewSpan = 0b1,
+ DeactivateNewSpan = 0b10,
+ NewSpanAsRoot = 0b100,
+ }
+
///
/// Gets the current span from the context.
///
@@ -86,7 +94,7 @@ public TelemetrySpan StartRootSpan(
IEnumerable? links = null,
DateTimeOffset startTime = default)
{
- return this.StartSpanHelper(false, name, kind, default, initialAttributes, links, startTime);
+ return this.StartSpanHelper(StartSpanBehaviors.NewSpanAsRoot | StartSpanBehaviors.DeactivateNewSpan, name, kind, default, initialAttributes, links, startTime);
}
///
@@ -132,7 +140,7 @@ public TelemetrySpan StartSpan(
IEnumerable? links = null,
DateTimeOffset startTime = default)
{
- return this.StartSpanHelper(false, name, kind, in parentContext, initialAttributes, links, startTime);
+ return this.StartSpanHelper(StartSpanBehaviors.DeactivateNewSpan, name, kind, in parentContext, initialAttributes, links, startTime);
}
///
@@ -178,7 +186,7 @@ public TelemetrySpan StartActiveSpan(
IEnumerable? links = null,
DateTimeOffset startTime = default)
{
- return this.StartSpanHelper(true, name, kind, in parentContext, initialAttributes, links, startTime);
+ return this.StartSpanHelper(StartSpanBehaviors.ActivateNewSpan, name, kind, in parentContext, initialAttributes, links, startTime);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -197,7 +205,7 @@ private static ActivityKind ConvertToActivityKind(SpanKind kind)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private TelemetrySpan StartSpanHelper(
- bool isActiveSpan,
+ StartSpanBehaviors startSpanBehavior,
string name,
SpanKind kind,
in SpanContext parentContext = default,
@@ -212,19 +220,28 @@ private TelemetrySpan StartSpanHelper(
var activityKind = ConvertToActivityKind(kind);
var activityLinks = links?.Select(l => l.ActivityLink);
- var previousActivity = !isActiveSpan ? Activity.Current : null;
+ var previousActivity = Activity.Current;
- var activity = this.ActivitySource.StartActivity(name, activityKind, parentContext.ActivityContext, initialAttributes?.Attributes ?? null, activityLinks, startTime);
- if (activity == null)
+ if (startSpanBehavior.HasFlag(StartSpanBehaviors.NewSpanAsRoot)
+ && previousActivity != null)
{
- return TelemetrySpan.NoopInstance;
+ Activity.Current = null;
}
- if (!isActiveSpan)
+ try
{
- Activity.Current = previousActivity;
+ var activity = this.ActivitySource.StartActivity(name, activityKind, parentContext.ActivityContext, initialAttributes?.Attributes ?? null, activityLinks, startTime);
+ return activity == null
+ ? TelemetrySpan.NoopInstance
+ : new TelemetrySpan(activity);
+ }
+ finally
+ {
+ if (startSpanBehavior.HasFlag(StartSpanBehaviors.DeactivateNewSpan)
+ && Activity.Current != previousActivity)
+ {
+ Activity.Current = previousActivity;
+ }
}
-
- return new TelemetrySpan(activity);
}
}
diff --git a/test/OpenTelemetry.Api.Tests/Trace/TracerTest.cs b/test/OpenTelemetry.Api.Tests/Trace/TracerTest.cs
index 221b66fc48c..115417efba8 100644
--- a/test/OpenTelemetry.Api.Tests/Trace/TracerTest.cs
+++ b/test/OpenTelemetry.Api.Tests/Trace/TracerTest.cs
@@ -71,7 +71,7 @@ public void Tracer_StartRootSpan_BadArgs_NullSpanName()
Assert.Null(span3.Activity.DisplayName);
}
- [Fact(Skip = "See https://github.com/open-telemetry/opentelemetry-dotnet/issues/2803")]
+ [Fact]
public async Task Tracer_StartRootSpan_StartsNewTrace()
{
var exportedItems = new List();