Skip to content

Commit 26b1ce0

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 26b1ce0

File tree

12 files changed

+136
-7
lines changed

12 files changed

+136
-7
lines changed

OpenTelemetry.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "experimental-apis", "experi
308308
docs\diagnostics\experimental-apis\OTEL1000.md = docs\diagnostics\experimental-apis\OTEL1000.md
309309
docs\diagnostics\experimental-apis\OTEL1001.md = docs\diagnostics\experimental-apis\OTEL1001.md
310310
docs\diagnostics\experimental-apis\OTEL1004.md = docs\diagnostics\experimental-apis\OTEL1004.md
311+
docs\diagnostics\experimental-apis\OTEL1005.md = docs\diagnostics\experimental-apis\OTEL1005.md
311312
docs\diagnostics\experimental-apis\README.md = docs\diagnostics\experimental-apis\README.md
312313
EndProjectSection
313314
EndProject

build/Common.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<NuGetAuditMode>all</NuGetAuditMode>
1313
<NuGetAuditLevel>low</NuGetAuditLevel>
1414
<!-- Suppress warnings for repo code using experimental features -->
15-
<NoWarn>$(NoWarn);OTEL1000;OTEL1001;OTEL1002;OTEL1004</NoWarn>
15+
<NoWarn>$(NoWarn);OTEL1000;OTEL1001;OTEL1002;OTEL1004;OTEL1005</NoWarn>
1616
<AnalysisLevel>latest-All</AnalysisLevel>
1717
</PropertyGroup>
1818

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# OpenTelemetry .NET Diagnostic: OTEL1004
2+
3+
## Overview
4+
5+
This is an experimental API for modifying spans before they end/close
6+
7+
### Details
8+
9+
#### ExtendedBaseProcessor
10+
11+
The abstract class `ExtendedBaseProcessor` provides an extension of the
12+
`BaseProcessor` that allows spans to be modified before they end as per the
13+
OpenTelemetry specification. It provides the `OnEnding` function that is called
14+
during the span `End()` operation. The end timestamp MUST have been computed
15+
(the `OnEnding` method duration is not included in the span duration). The Span
16+
object MUST still be mutable (i.e., `SetAttribute`, `AddLink`, `AddEvent` can be
17+
called) while `OnEnding` is called. This method MUST be called synchronously
18+
within the [`Span.End()` API](api.md#end), therefore it should not block or
19+
throw an exception. If multiple `SpanProcessors` are registered, their
20+
`OnEnding` callbacks are invoked in the order they have been registered. The
21+
SDK MUST guarantee that the span can no longer be modified by any other thread
22+
before invoking `OnEnding` of the first `SpanProcessor`. From that point on,
23+
modifications are only allowed synchronously from within the invoked `OnEnding`
24+
callbacks. All registered SpanProcessor `OnEnding` callbacks are executed before
25+
any SpanProcessor's `OnEnd` callback is invoked.
26+
27+
**Parameters:**
28+
29+
* `span` - a read/write span object for the span which is about to be ended.
30+
31+
**Returns:** `Void`

docs/diagnostics/experimental-apis/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ Description: ExemplarReservoir Support
3333

3434
Details: [OTEL1004](./OTEL1004.md)
3535

36+
### OTEL1005
37+
38+
Description: OnEnding Implementation
39+
40+
Details: [OTEL1005](./OTEL1005.md)
41+
3642
## Inactive
3743

3844
Experimental APIs which have been released stable or removed:

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+
[OTEL1005]OpenTelemetry.ExtendedBaseProcessor<T>
29+
[OTEL1005]OpenTelemetry.ExtendedBaseProcessor<T>.ExtendedBaseProcessor() -> void
30+
[OTEL1005]virtual OpenTelemetry.ExtendedBaseProcessor<T>.OnEnding(T data) -> void
31+
[OTEL1005]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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Copyright The OpenTelemetry Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4+
#if EXPOSE_EXPERIMENTAL_FEATURES
5+
using System.Diagnostics.CodeAnalysis;
6+
#endif
47
using System.Diagnostics;
58
using OpenTelemetry.Internal;
69

@@ -10,7 +13,11 @@ namespace OpenTelemetry;
1013
/// Represents a chain of <see cref="BaseProcessor{T}"/>s.
1114
/// </summary>
1215
/// <typeparam name="T">The type of object to be processed.</typeparam>
16+
#if EXPOSE_EXPERIMENTAL_FEATURES
17+
public class CompositeProcessor<T> : ExtendedBaseProcessor<T>
18+
#else
1319
public class CompositeProcessor<T> : BaseProcessor<T>
20+
#endif
1421
{
1522
internal readonly DoublyLinkedListNode Head;
1623
private DoublyLinkedListNode tail;
@@ -69,6 +76,21 @@ public override void OnEnd(T data)
6976
}
7077
}
7178

79+
#if EXPOSE_EXPERIMENTAL_FEATURES
80+
/// <inheritdoc/>
81+
[Experimental(DiagnosticDefinitions.ExtendedBaseProcessorExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
82+
public override void OnEnding(T data)
83+
{
84+
for (var cur = this.Head; cur != null; cur = cur.Next)
85+
{
86+
if (typeof(ExtendedBaseProcessor<T>).IsAssignableFrom(cur.Value.GetType()))
87+
{
88+
((ExtendedBaseProcessor<T>)cur.Value).OnEnding(data);
89+
}
90+
}
91+
}
92+
#endif
93+
7294
/// <inheritdoc/>
7395
public override void OnStart(T data)
7496
{
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#if EXPOSE_EXPERIMENTAL_FEATURES
5+
using System.Diagnostics.CodeAnalysis;
6+
using OpenTelemetry.Internal;
7+
8+
namespace OpenTelemetry;
9+
10+
/// <summary>
11+
/// Extended base processor base class.
12+
/// </summary>
13+
/// <typeparam name="T">The type of object to be processed.</typeparam>
14+
[Experimental(DiagnosticDefinitions.ExtendedBaseProcessorExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
15+
#pragma warning disable CA1012 // Abstract types should not have public constructors
16+
public abstract class ExtendedBaseProcessor<T> : BaseProcessor<T>
17+
#pragma warning restore CA1012 // Abstract types should not have public constructors
18+
{
19+
/// <summary>
20+
/// Called synchronously before a telemetry object ends.
21+
/// </summary>
22+
/// <param name="data">
23+
/// The started telemetry object.
24+
/// </param>
25+
/// <remarks>
26+
/// This function is called synchronously on the thread which ended
27+
/// the telemetry object. This function should be thread-safe, and
28+
/// should not block indefinitely or throw exceptions.
29+
/// </remarks>
30+
public virtual void OnEnding(T data)
31+
{
32+
}
33+
}
34+
#endif

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
};

src/Shared/DiagnosticDefinitions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ internal static class DiagnosticDefinitions
1010
public const string LoggerProviderExperimentalApi = "OTEL1000";
1111
public const string LogsBridgeExperimentalApi = "OTEL1001";
1212
public const string ExemplarReservoirExperimentalApi = "OTEL1004";
13+
public const string ExtendedBaseProcessorExperimentalApi = "OTEL1005";
1314

1415
/* Definitions which have been released stable:
1516
public const string ExemplarExperimentalApi = "OTEL1002";

0 commit comments

Comments
 (0)