From 72a255327ad3107755fe9c80b9362fad2a0b1e7f Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Tue, 21 May 2024 18:00:16 -0700 Subject: [PATCH 1/6] Provide better concurrency modes --- docs/logs/extending-the-sdk/MyExporter.cs | 1 + .../.publicApi/Stable/PublicAPI.Unshipped.txt | 7 +++ src/OpenTelemetry/ConcurrencyModes.cs | 43 +++++++++++++++++++ .../ConcurrencyModesAttribute.cs | 27 ++++++++++++ src/OpenTelemetry/SimpleExportProcessor.cs | 22 ++++++++++ 5 files changed, 100 insertions(+) create mode 100644 src/OpenTelemetry/ConcurrencyModes.cs create mode 100644 src/OpenTelemetry/ConcurrencyModesAttribute.cs diff --git a/docs/logs/extending-the-sdk/MyExporter.cs b/docs/logs/extending-the-sdk/MyExporter.cs index 6093f57394b..50f4caaa3c6 100644 --- a/docs/logs/extending-the-sdk/MyExporter.cs +++ b/docs/logs/extending-the-sdk/MyExporter.cs @@ -5,6 +5,7 @@ using OpenTelemetry; using OpenTelemetry.Logs; +[ConcurrencyModes(ConcurrencyModes.Multithreaded | ConcurrencyModes.Reentrant)] internal class MyExporter : BaseExporter { private readonly string name; diff --git a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt index a9a6c031d7a..d13a31cb0ce 100644 --- a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt @@ -1,3 +1,10 @@ +OpenTelemetry.ConcurrencyModes +OpenTelemetry.ConcurrencyModes.Global = 128 -> OpenTelemetry.ConcurrencyModes +OpenTelemetry.ConcurrencyModes.Multithreaded = 2 -> OpenTelemetry.ConcurrencyModes +OpenTelemetry.ConcurrencyModes.Reentrant = 1 -> OpenTelemetry.ConcurrencyModes +OpenTelemetry.ConcurrencyModesAttribute +OpenTelemetry.ConcurrencyModesAttribute.ConcurrencyModesAttribute(OpenTelemetry.ConcurrencyModes supported) -> void +OpenTelemetry.ConcurrencyModesAttribute.Supported.get -> OpenTelemetry.ConcurrencyModes OpenTelemetry.Metrics.Exemplar OpenTelemetry.Metrics.Exemplar.DoubleValue.get -> double OpenTelemetry.Metrics.Exemplar.Exemplar() -> void diff --git a/src/OpenTelemetry/ConcurrencyModes.cs b/src/OpenTelemetry/ConcurrencyModes.cs new file mode 100644 index 00000000000..e614db537d6 --- /dev/null +++ b/src/OpenTelemetry/ConcurrencyModes.cs @@ -0,0 +1,43 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +namespace OpenTelemetry; + +/// +/// Describes the concurrency mode of an OpenTelemetry extension. +/// +[Flags] +public enum ConcurrencyModes : byte +{ + /* + 0 0 0 0 0 0 0 0 + | | | | | | | | + | | | | | | | +--- Reentrant + | | | | | | +----- Multithreaded + | | | | | +------- (reserved) + | | | | +--------- (reserved) + | | | +----------- (reserved) + | | +------------- (reserved) + | +--------------- (reserved) + +----------------- Global + */ + + /// + /// Reentrant, the component can be invoked recursively without resulting + /// a deadlock or infinite loop. + /// + Reentrant = 0b1, + + /// + /// Multithreaded, the component can be invoked concurrently across + /// multiple threads. + /// + Multithreaded = 0b10, + + /// + /// Global, when combined with other flags, indicates that a per-instance + /// synchronization is insufficient, a global synchronization is required + /// across all instances of the component. + /// + Global = 0b10000000, +} diff --git a/src/OpenTelemetry/ConcurrencyModesAttribute.cs b/src/OpenTelemetry/ConcurrencyModesAttribute.cs new file mode 100644 index 00000000000..0a111a058d9 --- /dev/null +++ b/src/OpenTelemetry/ConcurrencyModesAttribute.cs @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +namespace OpenTelemetry; + +/// +/// An attribute for declaring the supported of an OpenTelemetry extension. +/// +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] +public sealed class ConcurrencyModesAttribute : Attribute +{ + private readonly ConcurrencyModes supportedConcurrencyModes; + + /// + /// Initializes a new instance of the class. + /// + /// . + public ConcurrencyModesAttribute(ConcurrencyModes supported) + { + this.supportedConcurrencyModes = supported; + } + + /// + /// Gets the supported . + /// + public ConcurrencyModes Supported => this.supportedConcurrencyModes; +} diff --git a/src/OpenTelemetry/SimpleExportProcessor.cs b/src/OpenTelemetry/SimpleExportProcessor.cs index 10951cd8533..e2be8da3835 100644 --- a/src/OpenTelemetry/SimpleExportProcessor.cs +++ b/src/OpenTelemetry/SimpleExportProcessor.cs @@ -13,6 +13,7 @@ public abstract class SimpleExportProcessor : BaseExportProcessor where T : class { private readonly object syncObject = new(); + private readonly ConcurrencyModes supportedConcurrencyModes; /// /// Initializes a new instance of the class. @@ -21,11 +22,32 @@ public abstract class SimpleExportProcessor : BaseExportProcessor protected SimpleExportProcessor(BaseExporter exporter) : base(exporter) { + var exporterType = exporter.GetType(); + var attributes = exporterType.GetCustomAttributes(typeof(ConcurrencyModesAttribute), true); + if (attributes.Length > 0) + { + var attr = (ConcurrencyModesAttribute)attributes[attributes.Length - 1]; + this.supportedConcurrencyModes = attr.Supported; + } } /// protected override void OnExport(T data) { + if (this.supportedConcurrencyModes.HasFlag(ConcurrencyModes.Multithreaded)) + { + try + { + this.exporter.Export(new Batch(data)); + } + catch (Exception ex) + { + OpenTelemetrySdkEventSource.Log.SpanProcessorException(nameof(this.OnExport), ex); + } + + return; + } + lock (this.syncObject) { try From 458faaf8afc009cb76385d4828ffba10fdec8ce0 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Wed, 22 May 2024 14:59:16 -0700 Subject: [PATCH 2/6] scope down --- docs/logs/extending-the-sdk/MyExporter.cs | 1 - .../.publicApi/Stable/PublicAPI.Unshipped.txt | 1 - src/OpenTelemetry/ConcurrencyModes.cs | 9 +-------- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/docs/logs/extending-the-sdk/MyExporter.cs b/docs/logs/extending-the-sdk/MyExporter.cs index 50f4caaa3c6..6093f57394b 100644 --- a/docs/logs/extending-the-sdk/MyExporter.cs +++ b/docs/logs/extending-the-sdk/MyExporter.cs @@ -5,7 +5,6 @@ using OpenTelemetry; using OpenTelemetry.Logs; -[ConcurrencyModes(ConcurrencyModes.Multithreaded | ConcurrencyModes.Reentrant)] internal class MyExporter : BaseExporter { private readonly string name; diff --git a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt index d13a31cb0ce..9e03908b3d6 100644 --- a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt @@ -1,5 +1,4 @@ OpenTelemetry.ConcurrencyModes -OpenTelemetry.ConcurrencyModes.Global = 128 -> OpenTelemetry.ConcurrencyModes OpenTelemetry.ConcurrencyModes.Multithreaded = 2 -> OpenTelemetry.ConcurrencyModes OpenTelemetry.ConcurrencyModes.Reentrant = 1 -> OpenTelemetry.ConcurrencyModes OpenTelemetry.ConcurrencyModesAttribute diff --git a/src/OpenTelemetry/ConcurrencyModes.cs b/src/OpenTelemetry/ConcurrencyModes.cs index e614db537d6..2c5373aa8b0 100644 --- a/src/OpenTelemetry/ConcurrencyModes.cs +++ b/src/OpenTelemetry/ConcurrencyModes.cs @@ -19,7 +19,7 @@ 0 0 0 0 0 0 0 0 | | | +----------- (reserved) | | +------------- (reserved) | +--------------- (reserved) - +----------------- Global + +----------------- (reserved) */ /// @@ -33,11 +33,4 @@ 0 0 0 0 0 0 0 0 /// multiple threads. /// Multithreaded = 0b10, - - /// - /// Global, when combined with other flags, indicates that a per-instance - /// synchronization is insufficient, a global synchronization is required - /// across all instances of the component. - /// - Global = 0b10000000, } From 67324bd6dc78139dfb78b18b91ac8f3a34e571dd Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Wed, 22 May 2024 15:07:35 -0700 Subject: [PATCH 3/6] clean up --- src/OpenTelemetry/SimpleExportProcessor.cs | 42 ++++++++++++---------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/OpenTelemetry/SimpleExportProcessor.cs b/src/OpenTelemetry/SimpleExportProcessor.cs index e2be8da3835..1de0f11b4c4 100644 --- a/src/OpenTelemetry/SimpleExportProcessor.cs +++ b/src/OpenTelemetry/SimpleExportProcessor.cs @@ -12,7 +12,7 @@ namespace OpenTelemetry; public abstract class SimpleExportProcessor : BaseExportProcessor where T : class { - private readonly object syncObject = new(); + private readonly object syncObject; private readonly ConcurrencyModes supportedConcurrencyModes; /// @@ -29,35 +29,39 @@ protected SimpleExportProcessor(BaseExporter exporter) var attr = (ConcurrencyModesAttribute)attributes[attributes.Length - 1]; this.supportedConcurrencyModes = attr.Supported; } + + if (!this.supportedConcurrencyModes.HasFlag(ConcurrencyModes.Multithreaded)) + { + this.syncObject = new object(); + } } /// protected override void OnExport(T data) { - if (this.supportedConcurrencyModes.HasFlag(ConcurrencyModes.Multithreaded)) + if (this.syncObject is null) { - try - { - this.exporter.Export(new Batch(data)); - } - catch (Exception ex) + this.OnExportInternal(data); + } + else + { + lock (this.syncObject) { - OpenTelemetrySdkEventSource.Log.SpanProcessorException(nameof(this.OnExport), ex); + this.OnExportInternal(data); } - - return; } + } - lock (this.syncObject) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void OnExportInternal(T data) + { + try { - try - { - this.exporter.Export(new Batch(data)); - } - catch (Exception ex) - { - OpenTelemetrySdkEventSource.Log.SpanProcessorException(nameof(this.OnExport), ex); - } + this.exporter.Export(new Batch(data)); + } + catch (Exception ex) + { + OpenTelemetrySdkEventSource.Log.SpanProcessorException(nameof(this.OnExport), ex); } } } From 08201f2f8e115dba5dacb3b0901a2a4d5d2b5187 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Wed, 22 May 2024 15:10:03 -0700 Subject: [PATCH 4/6] using --- src/OpenTelemetry/SimpleExportProcessor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OpenTelemetry/SimpleExportProcessor.cs b/src/OpenTelemetry/SimpleExportProcessor.cs index 1de0f11b4c4..6ff6820e4c6 100644 --- a/src/OpenTelemetry/SimpleExportProcessor.cs +++ b/src/OpenTelemetry/SimpleExportProcessor.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using System.Runtime.CompilerServices; using OpenTelemetry.Internal; namespace OpenTelemetry; From 608da98e6b3e3ef565e2ba92aeadb0e62b15aa15 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Wed, 22 May 2024 15:10:53 -0700 Subject: [PATCH 5/6] nullable --- src/OpenTelemetry/SimpleExportProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/SimpleExportProcessor.cs b/src/OpenTelemetry/SimpleExportProcessor.cs index 6ff6820e4c6..8dbe2042b20 100644 --- a/src/OpenTelemetry/SimpleExportProcessor.cs +++ b/src/OpenTelemetry/SimpleExportProcessor.cs @@ -13,7 +13,7 @@ namespace OpenTelemetry; public abstract class SimpleExportProcessor : BaseExportProcessor where T : class { - private readonly object syncObject; + private readonly object? syncObject; private readonly ConcurrencyModes supportedConcurrencyModes; /// From 3bad97575b56e3196ccf180877758bb67b9b029a Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Wed, 22 May 2024 16:34:36 -0700 Subject: [PATCH 6/6] changelog --- src/OpenTelemetry/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 763f3f370a0..891b62044f0 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +* Exposed `ConcurrencyModes` as a public contract for extensions (e.g. + exporters) to better express their concurrency requirements. + ([#5643](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5643)) + ## 1.9.0-alpha.1 Released 2024-May-20