diff --git a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs index 13db86eff8f..d579113331d 100644 --- a/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs +++ b/src/OpenTelemetry/Internal/Builder/ProviderBuilderServiceCollectionExtensions.cs @@ -28,6 +28,17 @@ namespace Microsoft.Extensions.DependencyInjection; internal static class ProviderBuilderServiceCollectionExtensions { + public static IServiceCollection AddOpenTelemetryLoggerProviderBuilderServices(this IServiceCollection services) + { + Debug.Assert(services != null, "services was null"); + + // TODO: + // services!.TryAddSingleton(); + // services!.RegisterOptionsFactory(configuration => new BatchExportLogRecordProcessorOptions(configuration)); + + return services!; + } + public static IServiceCollection AddOpenTelemetryMeterProviderBuilderServices(this IServiceCollection services) { Debug.Assert(services != null, "services was null"); diff --git a/src/OpenTelemetry/Logs/Builder/LoggerProviderServiceCollectionBuilder.cs b/src/OpenTelemetry/Logs/Builder/LoggerProviderServiceCollectionBuilder.cs new file mode 100644 index 00000000000..f90a387714a --- /dev/null +++ b/src/OpenTelemetry/Logs/Builder/LoggerProviderServiceCollectionBuilder.cs @@ -0,0 +1,138 @@ +// +// 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 Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Logs; + +/// +/// Contains methods for registering actions into an which will be used to build a once the is +/// available. +/// +internal sealed class LoggerProviderServiceCollectionBuilder : LoggerProviderBuilder, ILoggerProviderBuilder +{ + private readonly bool allowBuild; + private IServiceCollection? services; + + /// + /// Initializes a new instance of the class. + /// + public LoggerProviderServiceCollectionBuilder() + { + var services = new ServiceCollection(); + + services + .AddOpenTelemetrySharedProviderBuilderServices() + .AddOpenTelemetryLoggerProviderBuilderServices() + .TryAddSingleton( + sp => throw new NotSupportedException("Self-contained LoggerProvider cannot be accessed using the application IServiceProvider call Build instead.")); + + services.ConfigureOpenTelemetryLoggerProvider((sp, builder) => this.services = null); + + this.services = services; + + this.allowBuild = true; + } + + internal LoggerProviderServiceCollectionBuilder(IServiceCollection services) + { + Guard.ThrowIfNull(services); + + services + .AddOpenTelemetryLoggerProviderBuilderServices() + .TryAddSingleton(sp => new LoggerProviderSdk(sp, ownsServiceProvider: false)); + + services.ConfigureOpenTelemetryLoggerProvider((sp, builder) => this.services = null); + + this.services = services; + + this.allowBuild = false; + } + + /// + LoggerProvider? ILoggerProviderBuilder.Provider => null; + + /// + public override LoggerProviderBuilder AddInstrumentation(Func instrumentationFactory) + { + Guard.ThrowIfNull(instrumentationFactory); + + this.ConfigureBuilderInternal((sp, builder) => + { + builder.AddInstrumentation(instrumentationFactory); + }); + + return this; + } + + /// + LoggerProviderBuilder ILoggerProviderBuilder.ConfigureServices(Action configure) + => this.ConfigureServicesInternal(configure); + + /// + LoggerProviderBuilder IDeferredLoggerProviderBuilder.Configure(Action configure) + => this.ConfigureBuilderInternal(configure); + + internal LoggerProvider Build() + { + if (!this.allowBuild) + { + throw new NotSupportedException("A LoggerProviderBuilder bound to external service cannot be built directly. Access the LoggerProvider using the application IServiceProvider instead."); + } + + var services = this.services + ?? throw new NotSupportedException("LoggerProviderBuilder build method cannot be called multiple times."); + + this.services = null; + +#if DEBUG + bool validateScopes = true; +#else + bool validateScopes = false; +#endif + var serviceProvider = services.BuildServiceProvider(validateScopes); + + return new LoggerProviderSdk(serviceProvider, ownsServiceProvider: true); + } + + private LoggerProviderBuilder ConfigureBuilderInternal(Action configure) + { + var services = this.services + ?? throw new NotSupportedException("Builder cannot be configured during LoggerProvider construction."); + + services.ConfigureOpenTelemetryLoggerProvider(configure); + + return this; + } + + private LoggerProviderBuilder ConfigureServicesInternal(Action configure) + { + Guard.ThrowIfNull(configure); + + var services = this.services + ?? throw new NotSupportedException("Services cannot be configured during LoggerProvider construction."); + + configure(services); + + return this; + } +} diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLogger.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs similarity index 100% rename from src/OpenTelemetry/Logs/OpenTelemetryLogger.cs rename to src/OpenTelemetry/Logs/ILogger/OpenTelemetryLogger.cs diff --git a/src/OpenTelemetry/Logs/Options/OpenTelemetryLoggerOptions.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs similarity index 100% rename from src/OpenTelemetry/Logs/Options/OpenTelemetryLoggerOptions.cs rename to src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerProvider.cs similarity index 100% rename from src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs rename to src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerProvider.cs diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggingExtensions.cs similarity index 100% rename from src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs rename to src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggingExtensions.cs diff --git a/src/OpenTelemetry/Logs/LoggerProviderSdk.cs b/src/OpenTelemetry/Logs/LoggerProviderSdk.cs new file mode 100644 index 00000000000..5b108966aaa --- /dev/null +++ b/src/OpenTelemetry/Logs/LoggerProviderSdk.cs @@ -0,0 +1,29 @@ +// +// 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 + +namespace OpenTelemetry.Logs; + +internal sealed class LoggerProviderSdk : LoggerProvider +{ + public LoggerProviderSdk( + IServiceProvider serviceProvider, + bool ownsServiceProvider) + { + throw new NotImplementedException(); + } +} diff --git a/test/OpenTelemetry.AotCompatibility.Tests/AotCompatibilityTests.cs b/test/OpenTelemetry.AotCompatibility.Tests/AotCompatibilityTests.cs index 574cc1840c3..eab72ac9d0a 100644 --- a/test/OpenTelemetry.AotCompatibility.Tests/AotCompatibilityTests.cs +++ b/test/OpenTelemetry.AotCompatibility.Tests/AotCompatibilityTests.cs @@ -85,7 +85,7 @@ public void EnsureAotCompatibility() Assert.True(process.ExitCode == 0, "Publishing the AotCompatibility app failed. See test output for more details."); var warnings = expectedOutput.ToString().Split('\n', '\r').Where(line => line.Contains("warning IL")); - Assert.Equal(77, warnings.Count()); + Assert.Equal(78, warnings.Count()); } } }