diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderServiceCollectionHelper.cs b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionCallbackHelper.cs similarity index 63% rename from src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderServiceCollectionHelper.cs rename to src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionCallbackHelper.cs index 779e7f017f6..0e5d995a98e 100644 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderServiceCollectionHelper.cs +++ b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionCallbackHelper.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,13 +20,14 @@ using System.Diagnostics; using Microsoft.Extensions.DependencyInjection; -namespace OpenTelemetry.Metrics; +namespace OpenTelemetry; -internal static class MeterProviderBuilderServiceCollectionHelper +internal static class ProviderBuilderServiceCollectionCallbackHelper + where TState : ProviderBuilderState { - internal static IServiceCollection RegisterConfigureBuilderCallback( + public static IServiceCollection RegisterConfigureBuilderCallback( IServiceCollection services, - Action configure) + Action configure) { Debug.Assert(configure != null, "configure was null"); @@ -35,24 +36,25 @@ internal static IServiceCollection RegisterConfigureBuilderCallback( (sp, state) => configure!(sp, state.Builder)); } - internal static IServiceCollection RegisterConfigureStateCallback( + public static IServiceCollection RegisterConfigureStateCallback( IServiceCollection services, - Action configure) + Action configure) { Debug.Assert(services != null, "services was null"); Debug.Assert(configure != null, "configure was null"); - return services!.AddSingleton(new ConfigureMeterProviderBuilderStateCallbackRegistration(configure!)); + return services!.AddSingleton( + new ConfigureProviderBuilderStateCallbackRegistration(configure!)); } - internal static void InvokeRegisteredConfigureStateCallbacks( + public static void InvokeRegisteredConfigureStateCallbacks( IServiceProvider serviceProvider, - MeterProviderBuilderState state) + TState state) { Debug.Assert(serviceProvider != null, "serviceProvider was null"); Debug.Assert(state != null, "state was null"); - var callbackRegistrations = serviceProvider!.GetServices(); + var callbackRegistrations = serviceProvider!.GetServices(); foreach (var callbackRegistration in callbackRegistrations) { @@ -60,17 +62,17 @@ internal static void InvokeRegisteredConfigureStateCallbacks( } } - private sealed class ConfigureMeterProviderBuilderStateCallbackRegistration + private sealed class ConfigureProviderBuilderStateCallbackRegistration { - private readonly Action configure; + private readonly Action configure; - public ConfigureMeterProviderBuilderStateCallbackRegistration( - Action configure) + public ConfigureProviderBuilderStateCallbackRegistration( + Action configure) { this.configure = configure; } - public void Configure(IServiceProvider serviceProvider, MeterProviderBuilderState state) + public void Configure(IServiceProvider serviceProvider, TState state) { Debug.Assert(serviceProvider != null, "serviceProvider was null"); Debug.Assert(state != null, "state was null"); diff --git a/src/OpenTelemetry/Internal/Builder/ProviderBuilderState.cs b/src/OpenTelemetry/Internal/Builder/ProviderBuilderState.cs new file mode 100644 index 00000000000..3862f7a2120 --- /dev/null +++ b/src/OpenTelemetry/Internal/Builder/ProviderBuilderState.cs @@ -0,0 +1,107 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using OpenTelemetry.Resources; + +namespace OpenTelemetry; + +internal abstract class ProviderBuilderState +{ + private TProvider? provider; + + protected ProviderBuilderState(IServiceProvider serviceProvider) + { + Debug.Assert(serviceProvider != null, "serviceProvider was null"); + + this.ServiceProvider = serviceProvider!; + } + + public IServiceProvider ServiceProvider { get; } + + public abstract TBuilder Builder { get; } + + public TProvider Provider + { + get => this.provider ?? throw new InvalidOperationException("Provider has not been set on state."); + } + + public List Instrumentation { get; } = new(); + + public ResourceBuilder? ResourceBuilder { get; protected set; } + + public void RegisterProvider(string providerTypeName, TProvider provider) + { + Debug.Assert(provider != null, "provider was null"); + + if (this.provider != null) + { + throw new NotSupportedException($"{providerTypeName} cannot be accessed while build is executing."); + } + + this.provider = provider; + } + + public void AddInstrumentation( + string instrumentationName, + string instrumentationVersion, + object instrumentation) + { + Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationName), "instrumentationName was null or whitespace"); + Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationVersion), "instrumentationVersion was null or whitespace"); + Debug.Assert(instrumentation != null, "instrumentation was null"); + + this.Instrumentation.Add( + new InstrumentationRegistration( + instrumentationName, + instrumentationVersion, + instrumentation!)); + } + + public void ConfigureResource(Action configure) + { + Debug.Assert(configure != null, "configure was null"); + + var resourceBuilder = this.ResourceBuilder ??= ResourceBuilder.CreateDefault(); + + configure!(resourceBuilder); + } + + public void SetResourceBuilder(ResourceBuilder resourceBuilder) + { + Debug.Assert(resourceBuilder != null, "resourceBuilder was null"); + + this.ResourceBuilder = resourceBuilder; + } + + internal readonly struct InstrumentationRegistration + { + public readonly string Name; + public readonly string Version; + public readonly object Instance; + + internal InstrumentationRegistration(string name, string version, object instance) + { + this.Name = name; + this.Version = version; + this.Instance = instance; + } + } +} diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs index 14cdd0d408d..52cb6f9a780 100644 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs +++ b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderBase.cs @@ -25,6 +25,11 @@ using OpenTelemetry.Internal; using OpenTelemetry.Resources; +using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< + OpenTelemetry.Metrics.MeterProviderBuilderSdk, + OpenTelemetry.Metrics.MeterProviderSdk, + OpenTelemetry.Metrics.MeterProviderBuilderState>; + namespace OpenTelemetry.Metrics { /// @@ -103,7 +108,7 @@ MeterProviderBuilder IDeferredMeterProviderBuilder.Configure( else { this.ConfigureServices(services - => MeterProviderBuilderServiceCollectionHelper.RegisterConfigureBuilderCallback(services, configure)); + => CallbackHelper.RegisterConfigureBuilderCallback(services, configure)); } return this; @@ -292,7 +297,7 @@ private MeterProviderBuilder ConfigureState(Action MeterProviderBuilderServiceCollectionHelper.RegisterConfigureStateCallback(services, configure!)); + this.ConfigureServices(services => CallbackHelper.RegisterConfigureStateCallback(services, configure!)); } return this; diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderState.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderState.cs index 0a312eb35fb..ebd9b81e53b 100644 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderState.cs +++ b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderState.cs @@ -21,63 +21,36 @@ using System.Diagnostics; using System.Diagnostics.Metrics; using OpenTelemetry.Internal; -using OpenTelemetry.Resources; namespace OpenTelemetry.Metrics { /// /// Stores state used to build a . /// - internal sealed class MeterProviderBuilderState + internal sealed class MeterProviderBuilderState : ProviderBuilderState { - internal const int MaxMetricsDefault = 1000; - internal const int MaxMetricPointsPerMetricDefault = 2000; - internal readonly IServiceProvider ServiceProvider; - internal readonly List Instrumentation = new(); - internal readonly List Readers = new(); - internal readonly List MeterSources = new(); - internal readonly List> ViewConfigs = new(); - internal ResourceBuilder? ResourceBuilder; - internal int MaxMetricStreams = MaxMetricsDefault; - internal int MaxMetricPointsPerMetricStream = MaxMetricPointsPerMetricDefault; - - private bool hasEnteredBuildPhase; + public const int MaxMetricsDefault = 1000; + public const int MaxMetricPointsPerMetricDefault = 2000; + private MeterProviderBuilderSdk? builder; public MeterProviderBuilderState(IServiceProvider serviceProvider) + : base(serviceProvider) { - Debug.Assert(serviceProvider != null, "serviceProvider was null"); - - this.ServiceProvider = serviceProvider!; } - public MeterProviderBuilderSdk Builder => this.builder ??= new MeterProviderBuilderSdk(this); + public override MeterProviderBuilderSdk Builder + => this.builder ??= new MeterProviderBuilderSdk(this); - public void CheckForCircularBuild() - { - if (this.hasEnteredBuildPhase) - { - throw new NotSupportedException("MeterProvider cannot be accessed while build is executing."); - } + public List Readers { get; } = new(); - this.hasEnteredBuildPhase = true; - } + public List MeterSources { get; } = new(); - public void AddInstrumentation( - string instrumentationName, - string instrumentationVersion, - object instrumentation) - { - Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationName), "instrumentationName was null or whitespace"); - Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationVersion), "instrumentationVersion was null or whitespace"); - Debug.Assert(instrumentation != null, "instrumentation was null"); - - this.Instrumentation.Add( - new InstrumentationRegistration( - instrumentationName, - instrumentationVersion, - instrumentation!)); - } + public List> ViewConfigs { get; } = new(); + + public int MaxMetricStreams { get; set; } = MaxMetricsDefault; + + public int MaxMetricPointsPerMetricStream { get; set; } = MaxMetricPointsPerMetricDefault; public void AddMeter(params string[] names) { @@ -104,35 +77,5 @@ public void AddView(Func viewConfig) this.ViewConfigs.Add(viewConfig!); } - - public void ConfigureResource(Action configure) - { - Debug.Assert(configure != null, "configure was null"); - - var resourceBuilder = this.ResourceBuilder ??= ResourceBuilder.CreateDefault(); - - configure!(resourceBuilder); - } - - public void SetResourceBuilder(ResourceBuilder resourceBuilder) - { - Debug.Assert(resourceBuilder != null, "resourceBuilder was null"); - - this.ResourceBuilder = resourceBuilder; - } - - internal readonly struct InstrumentationRegistration - { - public readonly string Name; - public readonly string Version; - public readonly object Instance; - - internal InstrumentationRegistration(string name, string version, object instance) - { - this.Name = name; - this.Version = version; - this.Instance = instance; - } - } } } diff --git a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs index 3af2055349d..8a8ab77f9c8 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderSdk.cs @@ -26,6 +26,11 @@ using OpenTelemetry.Internal; using OpenTelemetry.Resources; +using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< + OpenTelemetry.Metrics.MeterProviderBuilderSdk, + OpenTelemetry.Metrics.MeterProviderSdk, + OpenTelemetry.Metrics.MeterProviderBuilderState>; + namespace OpenTelemetry.Metrics { internal sealed class MeterProviderSdk : MeterProvider @@ -49,7 +54,7 @@ internal MeterProviderSdk( Debug.Assert(serviceProvider != null, "serviceProvider was null"); var state = serviceProvider!.GetRequiredService(); - state.CheckForCircularBuild(); + state.RegisterProvider(nameof(MeterProvider), this); this.ServiceProvider = serviceProvider!; @@ -61,7 +66,7 @@ internal MeterProviderSdk( OpenTelemetrySdkEventSource.Log.MeterProviderSdkEvent("Building MeterProvider."); - MeterProviderBuilderServiceCollectionHelper.InvokeRegisteredConfigureStateCallbacks( + CallbackHelper.InvokeRegisteredConfigureStateCallbacks( serviceProvider!, state); diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs index 71ee6f9ec7e..372b411fc5b 100644 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs +++ b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderBase.cs @@ -24,6 +24,11 @@ using OpenTelemetry.Internal; using OpenTelemetry.Resources; +using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< + OpenTelemetry.Trace.TracerProviderBuilderSdk, + OpenTelemetry.Trace.TracerProviderSdk, + OpenTelemetry.Trace.TracerProviderBuilderState>; + namespace OpenTelemetry.Trace { /// @@ -112,7 +117,7 @@ TracerProviderBuilder IDeferredTracerProviderBuilder.Configure( else { this.ConfigureServices(services - => TracerProviderBuilderServiceCollectionHelper.RegisterConfigureBuilderCallback(services, configure)); + => CallbackHelper.RegisterConfigureBuilderCallback(services, configure)); } return this; @@ -327,7 +332,8 @@ private TracerProviderBuilder ConfigureState(Action TracerProviderBuilderServiceCollectionHelper.RegisterConfigureStateCallback(services, configure!)); + this.ConfigureServices(services => + CallbackHelper.RegisterConfigureStateCallback(services, configure!)); } return this; diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderServiceCollectionHelper.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderServiceCollectionHelper.cs deleted file mode 100644 index 5de52f1a495..00000000000 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderServiceCollectionHelper.cs +++ /dev/null @@ -1,81 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#nullable enable - -using System; -using System.Diagnostics; -using Microsoft.Extensions.DependencyInjection; - -namespace OpenTelemetry.Trace; - -internal static class TracerProviderBuilderServiceCollectionHelper -{ - internal static IServiceCollection RegisterConfigureBuilderCallback( - IServiceCollection services, - Action configure) - { - Debug.Assert(configure != null, "configure was null"); - - return RegisterConfigureStateCallback( - services, - (sp, state) => configure!(sp, state.Builder)); - } - - internal static IServiceCollection RegisterConfigureStateCallback( - IServiceCollection services, - Action configure) - { - Debug.Assert(services != null, "services was null"); - Debug.Assert(configure != null, "configure was null"); - - return services!.AddSingleton(new ConfigureTracerProviderBuilderStateCallbackRegistration(configure!)); - } - - internal static void InvokeRegisteredConfigureStateCallbacks( - IServiceProvider serviceProvider, - TracerProviderBuilderState state) - { - Debug.Assert(serviceProvider != null, "serviceProvider was null"); - Debug.Assert(state != null, "state was null"); - - var callbackRegistrations = serviceProvider!.GetServices(); - - foreach (var callbackRegistration in callbackRegistrations) - { - callbackRegistration.Configure(serviceProvider!, state!); - } - } - - private sealed class ConfigureTracerProviderBuilderStateCallbackRegistration - { - private readonly Action configure; - - public ConfigureTracerProviderBuilderStateCallbackRegistration( - Action configure) - { - this.configure = configure; - } - - public void Configure(IServiceProvider serviceProvider, TracerProviderBuilderState state) - { - Debug.Assert(serviceProvider != null, "serviceProvider was null"); - Debug.Assert(state != null, "state was null"); - - this.configure(serviceProvider!, state!); - } - } -} diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderState.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderState.cs index 22080b82f50..f446834249b 100644 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderState.cs +++ b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderState.cs @@ -20,61 +20,33 @@ using System.Collections.Generic; using System.Diagnostics; using OpenTelemetry.Internal; -using OpenTelemetry.Resources; namespace OpenTelemetry.Trace { /// /// Stores state used to build a . /// - internal sealed class TracerProviderBuilderState + internal sealed class TracerProviderBuilderState : ProviderBuilderState { - internal readonly IServiceProvider ServiceProvider; - internal readonly List Instrumentation = new(); - internal readonly List> Processors = new(); - internal readonly List Sources = new(); - internal readonly HashSet LegacyActivityOperationNames = new(StringComparer.OrdinalIgnoreCase); - internal ResourceBuilder? ResourceBuilder; - internal Sampler? Sampler; - internal bool SetErrorStatusOnException; - - private bool hasEnteredBuildPhase; private TracerProviderBuilderSdk? builder; public TracerProviderBuilderState(IServiceProvider serviceProvider) + : base(serviceProvider) { - Debug.Assert(serviceProvider != null, "serviceProvider was null"); - - this.ServiceProvider = serviceProvider!; } - public TracerProviderBuilderSdk Builder => this.builder ??= new TracerProviderBuilderSdk(this); + public override TracerProviderBuilderSdk Builder + => this.builder ??= new TracerProviderBuilderSdk(this); - public void CheckForCircularBuild() - { - if (this.hasEnteredBuildPhase) - { - throw new NotSupportedException("TracerProvider cannot be accessed while build is executing."); - } + public List> Processors { get; } = new(); - this.hasEnteredBuildPhase = true; - } + public List Sources { get; } = new(); - public void AddInstrumentation( - string instrumentationName, - string instrumentationVersion, - object instrumentation) - { - Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationName), "instrumentationName was null or whitespace"); - Debug.Assert(!string.IsNullOrWhiteSpace(instrumentationVersion), "instrumentationVersion was null or whitespace"); - Debug.Assert(instrumentation != null, "instrumentation was null"); - - this.Instrumentation.Add( - new InstrumentationRegistration( - instrumentationName, - instrumentationVersion, - instrumentation!)); - } + public HashSet LegacyActivityOperationNames { get; } = new(StringComparer.OrdinalIgnoreCase); + + public Sampler? Sampler { get; private set; } + + public bool SetErrorStatusOnException { get; set; } public void AddLegacySource(string operationName) { @@ -104,22 +76,6 @@ public void AddSource(params string[] names) } } - public void ConfigureResource(Action configure) - { - Debug.Assert(configure != null, "configure was null"); - - var resourceBuilder = this.ResourceBuilder ??= ResourceBuilder.CreateDefault(); - - configure!(resourceBuilder); - } - - public void SetResourceBuilder(ResourceBuilder resourceBuilder) - { - Debug.Assert(resourceBuilder != null, "resourceBuilder was null"); - - this.ResourceBuilder = resourceBuilder; - } - public void SetSampler(Sampler sampler) { Debug.Assert(sampler != null, "sampler was null"); @@ -138,19 +94,5 @@ internal void EnableErrorStatusOnException() throw new NotSupportedException($"'{nameof(TracerProviderBuilderExtensions.SetErrorStatusOnException)}' is not supported on this platform", ex); } } - - internal readonly struct InstrumentationRegistration - { - public readonly string Name; - public readonly string Version; - public readonly object Instance; - - internal InstrumentationRegistration(string name, string version, object instance) - { - this.Name = name; - this.Version = version; - this.Instance = instance; - } - } } } diff --git a/src/OpenTelemetry/Trace/TracerProviderSdk.cs b/src/OpenTelemetry/Trace/TracerProviderSdk.cs index dd84d81f4e4..476ece22229 100644 --- a/src/OpenTelemetry/Trace/TracerProviderSdk.cs +++ b/src/OpenTelemetry/Trace/TracerProviderSdk.cs @@ -26,6 +26,11 @@ using OpenTelemetry.Internal; using OpenTelemetry.Resources; +using CallbackHelper = OpenTelemetry.ProviderBuilderServiceCollectionCallbackHelper< + OpenTelemetry.Trace.TracerProviderBuilderSdk, + OpenTelemetry.Trace.TracerProviderSdk, + OpenTelemetry.Trace.TracerProviderBuilderState>; + namespace OpenTelemetry.Trace { internal sealed class TracerProviderSdk : TracerProvider @@ -49,7 +54,7 @@ internal TracerProviderSdk( Debug.Assert(serviceProvider != null, "serviceProvider was null"); var state = serviceProvider!.GetRequiredService(); - state.CheckForCircularBuild(); + state.RegisterProvider(nameof(TracerProvider), this); this.ServiceProvider = serviceProvider!; @@ -61,7 +66,7 @@ internal TracerProviderSdk( OpenTelemetrySdkEventSource.Log.TracerProviderSdkEvent("Building TracerProvider."); - TracerProviderBuilderServiceCollectionHelper.InvokeRegisteredConfigureStateCallbacks( + CallbackHelper.InvokeRegisteredConfigureStateCallbacks( serviceProvider!, state);