Skip to content

Commit e108c44

Browse files
committed
feat: add on ending span processor functionality
This change creates a new ExtendedBaseProcessor that allows users to implement onEnding functionality to their processor, as per the spec: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#onending
1 parent cb8d9e9 commit e108c44

File tree

7 files changed

+81
-7
lines changed

7 files changed

+81
-7
lines changed

src/OpenTelemetry/.publicApi/Experimental/PublicAPI.Unshipped.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ OpenTelemetry.Metrics.MetricStreamConfiguration.ExemplarReservoirFactory.set ->
2525
[OTEL1000]static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.UseOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action<OpenTelemetry.Logs.LoggerProviderBuilder!>? configureBuilder, System.Action<OpenTelemetry.Logs.OpenTelemetryLoggerOptions!>? configureOptions) -> Microsoft.Extensions.Logging.ILoggingBuilder!
2626
[OTEL1001]static OpenTelemetry.Sdk.CreateLoggerProviderBuilder() -> OpenTelemetry.Logs.LoggerProviderBuilder!
2727
[OTEL1004]virtual OpenTelemetry.Metrics.FixedSizeExemplarReservoir.OnCollected() -> void
28+
OpenTelemetry.ExtendedBaseProcessor<T>
29+
OpenTelemetry.ExtendedBaseProcessor<T>.ExtendedBaseProcessor() -> void
30+
virtual OpenTelemetry.ExtendedBaseProcessor<T>.OnEnding(T data) -> void
31+
override OpenTelemetry.CompositeProcessor<T>.OnEnding(T data) -> void

src/OpenTelemetry/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Notes](../../RELEASENOTES.md).
1515
* Add support for .NET 10.0.
1616
([#6307](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6307))
1717

18+
* feat: add on ending span processor functionality
19+
([#6617](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6617))
20+
1821
## 1.13.1
1922

2023
Released 2025-Oct-09

src/OpenTelemetry/CompositeProcessor.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace OpenTelemetry;
1010
/// Represents a chain of <see cref="BaseProcessor{T}"/>s.
1111
/// </summary>
1212
/// <typeparam name="T">The type of object to be processed.</typeparam>
13-
public class CompositeProcessor<T> : BaseProcessor<T>
13+
public class CompositeProcessor<T> : ExtendedBaseProcessor<T>
1414
{
1515
internal readonly DoublyLinkedListNode Head;
1616
private DoublyLinkedListNode tail;
@@ -69,6 +69,18 @@ public override void OnEnd(T data)
6969
}
7070
}
7171

72+
/// <inheritdoc/>
73+
public override void OnEnding(T data)
74+
{
75+
for (var cur = this.Head; cur != null; cur = cur.Next)
76+
{
77+
if (typeof(ExtendedBaseProcessor<T>).IsAssignableFrom(cur.Value.GetType()))
78+
{
79+
((ExtendedBaseProcessor<T>)cur.Value).OnEnding(data);
80+
}
81+
}
82+
}
83+
7284
/// <inheritdoc/>
7385
public override void OnStart(T data)
7486
{
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
namespace OpenTelemetry;
5+
6+
/// <summary>
7+
/// Extended base processor base class.
8+
/// </summary>
9+
/// <typeparam name="T">The type of object to be processed.</typeparam>
10+
#pragma warning disable CA1012 // Abstract types should not have public constructors
11+
public abstract class ExtendedBaseProcessor<T> : BaseProcessor<T>
12+
#pragma warning restore CA1012 // Abstract types should not have public constructors
13+
{
14+
/// <summary>
15+
/// Called synchronously before a telemetry object ends.
16+
/// </summary>
17+
/// <param name="data">
18+
/// The started telemetry object.
19+
/// </param>
20+
/// <remarks>
21+
/// This function is called synchronously on the thread which ended
22+
/// the telemetry object. This function should be thread-safe, and
23+
/// should not block indefinitely or throw exceptions.
24+
/// </remarks>
25+
public virtual void OnEnding(T data)
26+
{
27+
}
28+
}

src/OpenTelemetry/Trace/TracerProviderSdk.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ internal TracerProviderSdk(
189189

190190
if (SuppressInstrumentationScope.DecrementIfTriggered() == 0)
191191
{
192+
if (typeof(ExtendedBaseProcessor<Activity>).IsAssignableFrom(this.processor?.GetType()))
193+
{
194+
(this.processor as ExtendedBaseProcessor<Activity>)?.OnEnding(activity);
195+
}
196+
192197
this.processor?.OnEnd(activity);
193198
}
194199
};
@@ -224,6 +229,11 @@ internal TracerProviderSdk(
224229

225230
if (SuppressInstrumentationScope.DecrementIfTriggered() == 0)
226231
{
232+
if (typeof(ExtendedBaseProcessor<Activity>).IsAssignableFrom(this.processor?.GetType()))
233+
{
234+
(this.processor as ExtendedBaseProcessor<Activity>)?.OnEnding(activity);
235+
}
236+
227237
this.processor?.OnEnd(activity);
228238
}
229239
};

test/OpenTelemetry.Tests/Shared/TestActivityProcessor.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55

66
namespace OpenTelemetry.Tests;
77

8-
internal sealed class TestActivityProcessor : BaseProcessor<Activity>
8+
internal sealed class TestActivityProcessor : ExtendedBaseProcessor<Activity>
99
{
1010
public Action<Activity>? StartAction;
11+
public Action<Activity>? EndingAction;
1112
public Action<Activity>? EndAction;
1213

1314
public TestActivityProcessor()
@@ -20,6 +21,13 @@ public TestActivityProcessor(Action<Activity>? onStart, Action<Activity>? onEnd)
2021
this.EndAction = onEnd;
2122
}
2223

24+
public TestActivityProcessor(Action<Activity>? onStart, Action<Activity>? onEnding, Action<Activity>? onEnd)
25+
{
26+
this.StartAction = onStart;
27+
this.EndingAction = onEnding;
28+
this.EndAction = onEnd;
29+
}
30+
2331
public bool ShutdownCalled { get; private set; }
2432

2533
public bool ForceFlushCalled { get; private set; }
@@ -31,6 +39,11 @@ public override void OnStart(Activity span)
3139
this.StartAction?.Invoke(span);
3240
}
3341

42+
public override void OnEnding(Activity span)
43+
{
44+
this.EndingAction?.Invoke(span);
45+
}
46+
3447
public override void OnEnd(Activity span)
3548
{
3649
this.EndAction?.Invoke(span);

test/OpenTelemetry.Tests/Trace/CompositeActivityProcessorTests.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,38 @@ public void CompositeActivityProcessor_CallsAllProcessorSequentially()
2626
var result = string.Empty;
2727

2828
using var p1 = new TestActivityProcessor(
29-
activity => { result += "1"; },
30-
activity => { result += "3"; });
29+
activity => { result += "start1"; },
30+
activity => { result += "end1"; });
3131
using var p2 = new TestActivityProcessor(
32-
activity => { result += "2"; },
33-
activity => { result += "4"; });
32+
activity => { result += "start2"; },
33+
activity => { result += "ending2"; },
34+
activity => { result += "end2"; });
3435

3536
using var activity = new Activity("test");
3637

3738
using (var processor = new CompositeProcessor<Activity>([p1, p2]))
3839
{
3940
processor.OnStart(activity);
41+
processor.OnEnding(activity);
4042
processor.OnEnd(activity);
4143
}
4244

43-
Assert.Equal("1234", result);
45+
Assert.Equal("start1start2ending2end1end2", result);
4446
}
4547

4648
[Fact]
4749
public void CompositeActivityProcessor_ProcessorThrows()
4850
{
4951
using var p1 = new TestActivityProcessor(
5052
_ => throw new InvalidOperationException("Start exception"),
53+
_ => throw new InvalidOperationException("Ending exception"),
5154
_ => throw new InvalidOperationException("End exception"));
5255

5356
using var activity = new Activity("test");
5457

5558
using var processor = new CompositeProcessor<Activity>([p1]);
5659
Assert.Throws<InvalidOperationException>(() => { processor.OnStart(activity); });
60+
Assert.Throws<InvalidOperationException>(() => { processor.OnEnding(activity); });
5761
Assert.Throws<InvalidOperationException>(() => { processor.OnEnd(activity); });
5862
}
5963

0 commit comments

Comments
 (0)