-
Notifications
You must be signed in to change notification settings - Fork 859
[OpenTelemetry] Add OnEnding span processor functionality #6617
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,31 @@ | ||||||||||
| # OpenTelemetry .NET Diagnostic: OTEL1004 | ||||||||||
|
|
||||||||||
| ## Overview | ||||||||||
|
|
||||||||||
| This is an experimental API for modifying spans before they end/close | ||||||||||
|
|
||||||||||
| ### Details | ||||||||||
|
|
||||||||||
| #### ExtendedBaseProcessor | ||||||||||
|
|
||||||||||
| The abstract class `ExtendedBaseProcessor` provides an extension of the | ||||||||||
| `BaseProcessor` that allows spans to be modified before they end as per the | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| OpenTelemetry specification. It provides the `OnEnding` function that is called | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| during the span `End()` operation. The end timestamp MUST have been computed | ||||||||||
| (the `OnEnding` method duration is not included in the span duration). The Span | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| object MUST still be mutable (i.e., `SetAttribute`, `AddLink`, `AddEvent` can be | ||||||||||
| called) while `OnEnding` is called. This method MUST be called synchronously | ||||||||||
| within the [`Span.End()` API](api.md#end), therefore it should not block or | ||||||||||
| throw an exception. If multiple `SpanProcessors` are registered, their | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| `OnEnding` callbacks are invoked in the order they have been registered. The | ||||||||||
| SDK MUST guarantee that the span can no longer be modified by any other thread | ||||||||||
| before invoking `OnEnding` of the first `SpanProcessor`. From that point on, | ||||||||||
| modifications are only allowed synchronously from within the invoked `OnEnding` | ||||||||||
| callbacks. All registered SpanProcessor `OnEnding` callbacks are executed before | ||||||||||
| any SpanProcessor's `OnEnd` callback is invoked. | ||||||||||
|
Comment on lines
+24
to
+25
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
|
||||||||||
| **Parameters:** | ||||||||||
|
|
||||||||||
| * `span` - a read/write span object for the span which is about to be ended. | ||||||||||
|
|
||||||||||
| **Returns:** `Void` | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -33,6 +33,12 @@ Description: ExemplarReservoir Support | |||||
|
|
||||||
| Details: [OTEL1004](./OTEL1004.md) | ||||||
|
|
||||||
| ### OTEL1005 | ||||||
|
|
||||||
| Description: OnEnding Implementation | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| Details: [OTEL1005](./OTEL1005.md) | ||||||
|
|
||||||
| ## Inactive | ||||||
|
|
||||||
| Experimental APIs which have been released stable or removed: | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -37,6 +37,9 @@ Released 2025-Oct-21 | |||||
| * Add support for .NET 10.0. | ||||||
| ([#6307](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6307)) | ||||||
|
|
||||||
| * feat: add on ending span processor functionality | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs moving up to the unreleased section as we made a release yesterday so this is now in the wrong place.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please improve this document to talk about when users should implement OnEnd vs the new option. |
||||||
| ([#6617](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6617)) | ||||||
|
|
||||||
| ## 1.13.1 | ||||||
|
|
||||||
| Released 2025-Oct-09 | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,9 @@ | ||||||||||||||||||||||||||||||
| // Copyright The OpenTelemetry Authors | ||||||||||||||||||||||||||||||
| // SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| #if EXPOSE_EXPERIMENTAL_FEATURES | ||||||||||||||||||||||||||||||
| using System.Diagnostics.CodeAnalysis; | ||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||
| using System.Diagnostics; | ||||||||||||||||||||||||||||||
| using OpenTelemetry.Internal; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
@@ -10,7 +13,11 @@ namespace OpenTelemetry; | |||||||||||||||||||||||||||||
| /// Represents a chain of <see cref="BaseProcessor{T}"/>s. | ||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||
| /// <typeparam name="T">The type of object to be processed.</typeparam> | ||||||||||||||||||||||||||||||
| #if EXPOSE_EXPERIMENTAL_FEATURES | ||||||||||||||||||||||||||||||
| public class CompositeProcessor<T> : ExtendedBaseProcessor<T> | ||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checked the documentation and it should be OK to change the base class without making a breaking change as all the members in the new class aren't abstract. |
||||||||||||||||||||||||||||||
| #else | ||||||||||||||||||||||||||||||
| public class CompositeProcessor<T> : BaseProcessor<T> | ||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| internal readonly DoublyLinkedListNode Head; | ||||||||||||||||||||||||||||||
| private DoublyLinkedListNode tail; | ||||||||||||||||||||||||||||||
|
|
@@ -69,6 +76,21 @@ public override void OnEnd(T data) | |||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| #if EXPOSE_EXPERIMENTAL_FEATURES | ||||||||||||||||||||||||||||||
| /// <inheritdoc/> | ||||||||||||||||||||||||||||||
| [Experimental(DiagnosticDefinitions.ExtendedBaseProcessorExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)] | ||||||||||||||||||||||||||||||
| public override void OnEnding(T data) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| for (var cur = this.Head; cur != null; cur = cur.Next) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| if (typeof(ExtendedBaseProcessor<T>).IsAssignableFrom(cur.Value.GetType())) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| ((ExtendedBaseProcessor<T>)cur.Value).OnEnding(data); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+84
to
+90
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this work to avoid reflection and casting?
Suggested change
|
||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /// <inheritdoc/> | ||||||||||||||||||||||||||||||
| public override void OnStart(T data) | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,34 @@ | ||||||
| // Copyright The OpenTelemetry Authors | ||||||
| // SPDX-License-Identifier: Apache-2.0 | ||||||
|
|
||||||
| #if EXPOSE_EXPERIMENTAL_FEATURES | ||||||
| using System.Diagnostics.CodeAnalysis; | ||||||
| using OpenTelemetry.Internal; | ||||||
|
|
||||||
| namespace OpenTelemetry; | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Extended base processor base class. | ||||||
| /// </summary> | ||||||
| /// <typeparam name="T">The type of object to be processed.</typeparam> | ||||||
| [Experimental(DiagnosticDefinitions.ExtendedBaseProcessorExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)] | ||||||
| #pragma warning disable CA1012 // Abstract types should not have public constructors | ||||||
| public abstract class ExtendedBaseProcessor<T> : BaseProcessor<T> | ||||||
| #pragma warning restore CA1012 // Abstract types should not have public constructors | ||||||
|
Comment on lines
+15
to
+17
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be fixed by adding an explicit |
||||||
| { | ||||||
| /// <summary> | ||||||
| /// Called synchronously before a telemetry object ends. | ||||||
| /// </summary> | ||||||
| /// <param name="data"> | ||||||
| /// The started telemetry object. | ||||||
| /// </param> | ||||||
| /// <remarks> | ||||||
| /// This function is called synchronously on the thread which ended | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| /// the telemetry object. This function should be thread-safe, and | ||||||
| /// should not block indefinitely or throw exceptions. | ||||||
| /// </remarks> | ||||||
| public virtual void OnEnding(T data) | ||||||
| { | ||||||
| } | ||||||
| } | ||||||
| #endif | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -189,6 +189,12 @@ internal TracerProviderSdk( | |||||||||||||||||
|
|
||||||||||||||||||
| if (SuppressInstrumentationScope.DecrementIfTriggered() == 0) | ||||||||||||||||||
| { | ||||||||||||||||||
| #if EXPOSE_EXPERIMENTAL_FEATURES | ||||||||||||||||||
| if (typeof(ExtendedBaseProcessor<Activity>).IsAssignableFrom(this.processor?.GetType())) | ||||||||||||||||||
| { | ||||||||||||||||||
| (this.processor as ExtendedBaseProcessor<Activity>)?.OnEnding(activity); | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+193
to
+196
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
| #endif | ||||||||||||||||||
| this.processor?.OnEnd(activity); | ||||||||||||||||||
| } | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
@@ -224,6 +230,13 @@ internal TracerProviderSdk( | |||||||||||||||||
|
|
||||||||||||||||||
| if (SuppressInstrumentationScope.DecrementIfTriggered() == 0) | ||||||||||||||||||
| { | ||||||||||||||||||
| #if EXPOSE_EXPERIMENTAL_FEATURES | ||||||||||||||||||
| if (typeof(ExtendedBaseProcessor<Activity>).IsAssignableFrom(this.processor?.GetType())) | ||||||||||||||||||
| { | ||||||||||||||||||
| (this.processor as ExtendedBaseProcessor<Activity>)?.OnEnding(activity); | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+234
to
+237
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
| #endif | ||||||||||||||||||
|
|
||||||||||||||||||
| this.processor?.OnEnd(activity); | ||||||||||||||||||
| } | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.