diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index 9463e1c3aaf..5d438fc9dc9 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -1,4 +1,12 @@ Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions +OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions +OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions.BatchExportLogRecordProcessorOptions() -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.BatchExportProcessorOptions.get -> OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions! +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.BatchExportProcessorOptions.set -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportLogRecordProcessorOptions() -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportProcessorType.set -> void OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void @@ -8,6 +16,10 @@ OpenTelemetry.Logs.LogRecord.Timestamp.set -> void OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void OpenTelemetry.Logs.LogRecord.TraceId.set -> void OpenTelemetry.Logs.LogRecord.TraceState.set -> void +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddProcessor() -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureProvider(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 9463e1c3aaf..5d438fc9dc9 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -1,4 +1,12 @@ Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions +OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions +OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions.BatchExportLogRecordProcessorOptions() -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.BatchExportProcessorOptions.get -> OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions! +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.BatchExportProcessorOptions.set -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportLogRecordProcessorOptions() -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportProcessorType.set -> void OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void @@ -8,6 +16,10 @@ OpenTelemetry.Logs.LogRecord.Timestamp.set -> void OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void OpenTelemetry.Logs.LogRecord.TraceId.set -> void OpenTelemetry.Logs.LogRecord.TraceState.set -> void +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddProcessor() -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureProvider(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index f6977a98165..7f9f3ed4692 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,4 +1,12 @@ Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions +OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions +OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions.BatchExportLogRecordProcessorOptions() -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.BatchExportProcessorOptions.get -> OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions! +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.BatchExportProcessorOptions.set -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportLogRecordProcessorOptions() -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportProcessorType.set -> void OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void @@ -8,6 +16,10 @@ OpenTelemetry.Logs.LogRecord.Timestamp.set -> void OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void OpenTelemetry.Logs.LogRecord.TraceId.set -> void OpenTelemetry.Logs.LogRecord.TraceState.set -> void +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddProcessor() -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureProvider(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureServices(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 9463e1c3aaf..5d438fc9dc9 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -1,4 +1,12 @@ Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions +OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions +OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions.BatchExportLogRecordProcessorOptions() -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.BatchExportProcessorOptions.get -> OpenTelemetry.Logs.BatchExportLogRecordProcessorOptions! +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.BatchExportProcessorOptions.set -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportLogRecordProcessorOptions() -> void +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType +OpenTelemetry.Logs.ExportLogRecordProcessorOptions.ExportProcessorType.set -> void OpenTelemetry.Logs.LogRecord.CategoryName.set -> void OpenTelemetry.Logs.LogRecord.EventId.set -> void OpenTelemetry.Logs.LogRecord.Exception.set -> void @@ -8,6 +16,10 @@ OpenTelemetry.Logs.LogRecord.Timestamp.set -> void OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void OpenTelemetry.Logs.LogRecord.TraceId.set -> void OpenTelemetry.Logs.LogRecord.TraceState.set -> void +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, OpenTelemetry.BaseExporter! exporter, System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddExporter(OpenTelemetry.ExportProcessorType exportProcessorType, System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.AddProcessor() -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureProvider(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 3c83f2bb6be..8090c32012a 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -11,6 +11,10 @@ * Added support for `UpDownCounter` and `ObservableUpDownCounter` instruments. ([#3606](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3606)) +* Added `AddExporter` `OpenTelemetryLoggerOptions` methods and further refined + the `OpenTelemetryLoggerProvider` dependency injection scenarios + ([#3596](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3596)) + ## 1.4.0-alpha.2 Released 2022-Aug-18 diff --git a/src/OpenTelemetry/Logs/BatchExportLogRecordProcessorOptions.cs b/src/OpenTelemetry/Logs/BatchExportLogRecordProcessorOptions.cs new file mode 100644 index 00000000000..f0a30da0d5e --- /dev/null +++ b/src/OpenTelemetry/Logs/BatchExportLogRecordProcessorOptions.cs @@ -0,0 +1,75 @@ +// +// 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. +// + +using System; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Logs +{ + /// + /// Batch log processor options. OTEL_DOTNET_BLP_MAX_QUEUE_SIZE, + /// OTEL_DOTNET_BLP_MAX_EXPORT_BATCH_SIZE, OTEL_DOTNET_BLP_EXPORT_TIMEOUT, + /// OTEL_DOTNET_BLP_SCHEDULE_DELAY environment variables are parsed during + /// object construction. + /// + /// + /// Notes: + /// + /// The constructor throws if it fails + /// to parse any of the supported environment variables. + /// The environment variable keys are currently experimental and + /// subject to change. See: OpenTelemetry + /// Environment Variable Specification. + /// + /// + /// + public class BatchExportLogRecordProcessorOptions : BatchExportProcessorOptions + { + internal const string MaxQueueSizeEnvVarKey = "OTEL_DOTNET_BLP_MAX_QUEUE_SIZE"; + + internal const string MaxExportBatchSizeEnvVarKey = "OTEL_DOTNET_BLP_MAX_EXPORT_BATCH_SIZE"; + + internal const string ExporterTimeoutEnvVarKey = "OTEL_DOTNET_BLP_EXPORT_TIMEOUT"; + + internal const string ScheduledDelayEnvVarKey = "OTEL_DOTNET_BLP_SCHEDULE_DELAY"; + + public BatchExportLogRecordProcessorOptions() + { + int value; + + if (EnvironmentVariableHelper.LoadNumeric(ExporterTimeoutEnvVarKey, out value)) + { + this.ExporterTimeoutMilliseconds = value; + } + + if (EnvironmentVariableHelper.LoadNumeric(MaxExportBatchSizeEnvVarKey, out value)) + { + this.MaxExportBatchSize = value; + } + + if (EnvironmentVariableHelper.LoadNumeric(MaxQueueSizeEnvVarKey, out value)) + { + this.MaxQueueSize = value; + } + + if (EnvironmentVariableHelper.LoadNumeric(ScheduledDelayEnvVarKey, out value)) + { + this.ScheduledDelayMilliseconds = value; + } + } + } +} diff --git a/src/OpenTelemetry/Logs/ExportLogRecordProcessorOptions.cs b/src/OpenTelemetry/Logs/ExportLogRecordProcessorOptions.cs new file mode 100644 index 00000000000..0915997de27 --- /dev/null +++ b/src/OpenTelemetry/Logs/ExportLogRecordProcessorOptions.cs @@ -0,0 +1,45 @@ +// +// 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 OpenTelemetry.Internal; + +namespace OpenTelemetry.Logs; + +public class ExportLogRecordProcessorOptions +{ + private BatchExportLogRecordProcessorOptions? batchExportProcessorOptions; + + /// + /// Gets or sets the export processor type to be used. The default value is . + /// + public ExportProcessorType ExportProcessorType { get; set; } + + /// + /// Gets or sets the batch export options. Ignored unless is . + /// + public BatchExportLogRecordProcessorOptions BatchExportProcessorOptions + { + get => this.batchExportProcessorOptions ??= new(); + set + { + Guard.ThrowIfNull(value); + + this.batchExportProcessorOptions = value; + } + } +} diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs index 7b438b264ae..0017f26a258 100644 --- a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs @@ -70,12 +70,6 @@ public OpenTelemetryLoggerProvider() { } - // Note: This is only for tests. Options will be missing ServiceCollection & ServiceProvider features will be unavailable. - internal OpenTelemetryLoggerProvider(OpenTelemetryLoggerOptions options) - : this(options, serviceProvider: null, ownsServiceProvider: false) - { - } - internal OpenTelemetryLoggerProvider(OpenTelemetryLoggerOptions options, IServiceProvider? serviceProvider, bool ownsServiceProvider) { Guard.ThrowIfNull(options); @@ -91,33 +85,11 @@ internal OpenTelemetryLoggerProvider(OpenTelemetryLoggerOptions options, IServic Debug.Assert(this.ownedServiceProvider != null, "ownedServiceProvider was null"); } - // Step 1: Add any processors added to options. - - foreach (var processor in options.Processors) - { - this.AddProcessor(processor); - } - - this.ResourceBuilder = options.ResourceBuilder ?? ResourceBuilder.CreateDefault(); - - if (serviceProvider != null) - { - // Step 2: Look for any Action configuration actions registered and - // execute them. - - var registeredConfigurations = serviceProvider.GetServices>(); - foreach (var registeredConfiguration in registeredConfigurations) - { - registeredConfiguration?.Invoke(serviceProvider, this); - } - } + this.ResourceBuilder ??= ResourceBuilder.CreateDefault(); var configurationActions = options.ConfigurationActions; if (configurationActions?.Count > 0) { - // Step 3: Execute any configuration actions. - if (serviceProvider == null) { throw new InvalidOperationException("Configuration actions were registered on options but no service provider was supplied."); @@ -133,17 +105,6 @@ internal OpenTelemetryLoggerProvider(OpenTelemetryLoggerOptions options, IServic options.ConfigurationActions = null; } - if (serviceProvider != null) - { - // Step 4: Look for any processors registered directly with the service provider. - - var registeredProcessors = serviceProvider.GetServices>(); - foreach (BaseProcessor processor in registeredProcessors) - { - this.AddProcessor(processor); - } - } - this.Resource = this.ResourceBuilder.Build(); this.ResourceBuilder = null; } diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs index 5a1d80f81e9..2107b04286d 100644 --- a/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs @@ -17,7 +17,6 @@ #nullable enable using System; -using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; @@ -37,9 +36,9 @@ public static class OpenTelemetryLoggingExtensions /// Adds an OpenTelemetry logger named 'OpenTelemetry' to the . /// /// - /// Note: This is safe to be called more than once and should be used by - /// library authors to ensure at least one is registered. + /// Note: This is safe to be called multiple times and by library + /// authors. Only a single + /// will be created for a given . /// /// The to use. /// The supplied for call chaining. @@ -49,11 +48,7 @@ public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder) /// /// Adds an OpenTelemetry logger named 'OpenTelemetry' to the . /// - /// - /// Note: This is should only be called once during application - /// bootstrap for a given . This should - /// not be used by library authors. - /// + /// /// The to use. /// Optional configuration action. /// The supplied for call chaining. @@ -65,12 +60,6 @@ public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, Act builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton(sp => { - var registeredBuilders = sp.GetServices(); - if (registeredBuilders.Count() > 1) - { - throw new NotSupportedException("Multiple logger provider builders cannot be registered in the same service collection."); - } - var finalOptions = sp.GetRequiredService>().CurrentValue; return new OpenTelemetryLoggerProvider(finalOptions, sp, ownsServiceProvider: false); @@ -94,8 +83,6 @@ public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, Act configure(options); - builder.Services.AddSingleton(new TrackedOpenTelemetryLoggerOptions(options)); - /* * Step 2: When ServiceProvider is built from "Services" and the * LoggerFactory is created then the options pipeline runs and @@ -119,9 +106,19 @@ public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, Act /// Adds an OpenTelemetry logger named 'OpenTelemetry' to the . /// /// - /// Note: The supplied will + /// Notes: + /// + /// + /// The supplied will /// automatically be disposed when the /// built from is disposed. + /// + /// + /// Only a single can be + /// registered for a given . Additional + /// calls to this method will be ignored. + /// + /// /// /// The to use. /// . @@ -132,6 +129,11 @@ public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, Ope /// /// Adds an OpenTelemetry logger named 'OpenTelemetry' to the . /// + /// + /// Note: Only a single can be + /// registered for a given . Additional + /// calls to this method will be ignored. + /// /// The to use. /// . /// Controls whether or not the supplied @@ -161,15 +163,5 @@ public static ILoggingBuilder AddOpenTelemetry( return builder; } - - private sealed class TrackedOpenTelemetryLoggerOptions - { - public TrackedOpenTelemetryLoggerOptions(OpenTelemetryLoggerOptions options) - { - this.Options = options; - } - - public OpenTelemetryLoggerOptions Options { get; } - } } } diff --git a/src/OpenTelemetry/Logs/Options/OpenTelemetryLoggerOptions.cs b/src/OpenTelemetry/Logs/Options/OpenTelemetryLoggerOptions.cs index 6be36c3a2e9..30575914e04 100644 --- a/src/OpenTelemetry/Logs/Options/OpenTelemetryLoggerOptions.cs +++ b/src/OpenTelemetry/Logs/Options/OpenTelemetryLoggerOptions.cs @@ -32,8 +32,6 @@ namespace OpenTelemetry.Logs /// public class OpenTelemetryLoggerOptions { - internal readonly List> Processors = new(); - internal ResourceBuilder? ResourceBuilder; internal List>? ConfigurationActions = new(); private const bool DefaultIncludeScopes = false; @@ -113,7 +111,7 @@ public OpenTelemetryLoggerOptions AddProcessor(BaseProcessor processo { Guard.ThrowIfNull(processor); - this.Processors.Add(processor); + this.ConfigureProvider((sp, provider) => provider.AddProcessor(processor)); return this; } @@ -126,36 +124,108 @@ public OpenTelemetryLoggerOptions AddProcessor(BaseProcessor processo /// registered as a singleton service into application services. /// /// Processor type. - /// The supplied for chaining. + /// Returns for chaining. public OpenTelemetryLoggerOptions AddProcessor() where T : BaseProcessor { - return this - .ConfigureServices(services => services.TryAddSingleton, T>()); + this.TryAddSingleton(); + this.ConfigureProvider((sp, provider) => provider.AddProcessor(sp.GetRequiredService())); + + return this; + } + + /// + /// Adds an exporter to the provider. + /// + /// . + /// LogRecord exporter to add. + /// Returns for chaining. + public OpenTelemetryLoggerOptions AddExporter(ExportProcessorType exportProcessorType, BaseExporter exporter) + => this.AddExporter(exportProcessorType, exporter, o => { }); + + /// + /// Adds an exporter to the provider. + /// + /// . + /// LogRecord exporter to add. + /// Callback action to configure . Only invoked when is . + /// Returns for chaining. + public OpenTelemetryLoggerOptions AddExporter(ExportProcessorType exportProcessorType, BaseExporter exporter, Action configure) + { + Guard.ThrowIfNull(exporter); + Guard.ThrowIfNull(configure); + + this.ConfigureProvider((sp, provider) + => provider.AddProcessor( + BuildExportProcessor(sp, exportProcessorType, exporter, configure))); + + return this; } /// - /// Sets the from which the Resource associated with + /// Adds an exporter to the provider which will be retrieved using dependency injection. + /// + /// + /// Note: The type specified by will be + /// registered as a singleton service into application services. + /// + /// Exporter type. + /// . + /// Returns for chaining. + public OpenTelemetryLoggerOptions AddExporter(ExportProcessorType exportProcessorType) + where T : BaseExporter + => this.AddExporter(exportProcessorType, o => { }); + + /// + /// Adds an exporter to the provider which will be retrieved using dependency injection. + /// + /// + /// Note: The type specified by will be + /// registered as a singleton service into application services. + /// + /// Exporter type. + /// . + /// Callback action to configure . Only invoked when is . + /// Returns for chaining. + public OpenTelemetryLoggerOptions AddExporter(ExportProcessorType exportProcessorType, Action configure) + where T : BaseExporter + { + Guard.ThrowIfNull(configure); + + this.TryAddSingleton(); + this.ConfigureProvider((sp, provider) + => provider.AddProcessor( + BuildExportProcessor(sp, exportProcessorType, sp.GetRequiredService(), configure))); + + return this; + } + + /// + /// Sets the from which the Resource associated with /// this provider is built from. Overwrites currently set ResourceBuilder. /// You should usually use instead /// (call if desired). /// - /// from which Resource will be built. + /// from which Resource will be built. /// Returns for chaining. public OpenTelemetryLoggerOptions SetResourceBuilder(ResourceBuilder resourceBuilder) { Guard.ThrowIfNull(resourceBuilder); - this.ResourceBuilder = resourceBuilder; - - return this; + return this.ConfigureProvider((sp, provider) => provider.ResourceBuilder = resourceBuilder); } /// - /// Modify the from which the Resource associated with + /// Modify the from which the Resource associated with /// this provider is built from in-place. /// - /// An action which modifies the provided in-place. + /// An action which modifies the provided in-place. /// Returns for chaining. public OpenTelemetryLoggerOptions ConfigureResource( Action configure) @@ -271,7 +341,7 @@ internal OpenTelemetryLoggerProvider Build() if (services == null) { - throw new NotSupportedException("LoggerProviderBuilder build method cannot be called multiple times."); + throw new NotSupportedException("OpenTelemetryLoggerOptions build method cannot be called multiple times."); } this.services = null; @@ -296,11 +366,6 @@ internal void ApplyTo(OpenTelemetryLoggerOptions other) { Debug.Assert(other != null, "other instance was null"); - if (this.ResourceBuilder != null) - { - other!.ResourceBuilder = this.ResourceBuilder; - } - if (this.includeFormattedMessage.HasValue) { other!.includeFormattedMessage = this.includeFormattedMessage; @@ -316,18 +381,54 @@ internal void ApplyTo(OpenTelemetryLoggerOptions other) other!.parseStateValues = this.parseStateValues; } - Debug.Assert(this.Processors != null && other!.Processors != null, "Processors was null"); + Debug.Assert(this.ConfigurationActions != null && other!.ConfigurationActions != null, "ConfigurationActions was null"); - foreach (var processor in this.Processors!) + foreach (var configurationAction in this.ConfigurationActions!) { - other!.Processors!.Add(processor); + other!.ConfigurationActions!.Add(configurationAction); } + } - Debug.Assert(this.ConfigurationActions != null && other!.ConfigurationActions != null, "ConfigurationActions was null"); + private static BaseProcessor BuildExportProcessor( + IServiceProvider serviceProvider, + ExportProcessorType exportProcessorType, + BaseExporter exporter, + Action configure) + { + switch (exportProcessorType) + { + case ExportProcessorType.Simple: + return new SimpleLogRecordExportProcessor(exporter); + case ExportProcessorType.Batch: + var options = new ExportLogRecordProcessorOptions + { + ExportProcessorType = ExportProcessorType.Batch, + BatchExportProcessorOptions = serviceProvider.GetRequiredService>().Value, + }; + + configure(options); + + var batchOptions = options.BatchExportProcessorOptions; + + return new BatchLogRecordExportProcessor( + exporter, + batchOptions.MaxQueueSize, + batchOptions.ScheduledDelayMilliseconds, + batchOptions.ExporterTimeoutMilliseconds, + batchOptions.MaxExportBatchSize); + default: + throw new NotSupportedException($"ExportProcessorType '{exportProcessorType}' is not supported."); + } + } - foreach (var configurationAction in this.ConfigurationActions!) + private void TryAddSingleton() + where T : class + { + var services = this.services; + + if (services != null) { - other!.ConfigurationActions!.Add(configurationAction); + services.TryAddSingleton(); } } } diff --git a/test/OpenTelemetry.Tests/Logs/LoggerOptionsTest.cs b/test/OpenTelemetry.Tests/Logs/LoggerOptionsTest.cs index 689bf1dce8c..aacc1e82f2a 100644 --- a/test/OpenTelemetry.Tests/Logs/LoggerOptionsTest.cs +++ b/test/OpenTelemetry.Tests/Logs/LoggerOptionsTest.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace OpenTelemetry.Logs.Tests @@ -25,19 +26,26 @@ public sealed class LoggerOptionsTest [InlineData(false)] public void VerifyOptionsCannotBeChangedAfterInit(bool initialValue) { - var options = new OpenTelemetryLoggerOptions - { - IncludeFormattedMessage = initialValue, - IncludeScopes = initialValue, - ParseStateValues = initialValue, - }; - var provider = new OpenTelemetryLoggerProvider(options); + OpenTelemetryLoggerOptions options = null; + + using var provider = Sdk.CreateLoggerProviderBuilder() + .ConfigureServices(services => services.Configure(o => + { + options = o; + + o.IncludeFormattedMessage = initialValue; + o.IncludeScopes = initialValue; + o.ParseStateValues = initialValue; + })) + .Build(); // Verify initial set Assert.Equal(initialValue, provider.IncludeFormattedMessage); Assert.Equal(initialValue, provider.IncludeScopes); Assert.Equal(initialValue, provider.ParseStateValues); + Assert.NotNull(options); + // Attempt to change value options.IncludeFormattedMessage = !initialValue; options.IncludeScopes = !initialValue; diff --git a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerOptionsSdkTests.cs b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerOptionsSdkTests.cs index b62080951c3..bb9d1a3fa7b 100644 --- a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerOptionsSdkTests.cs +++ b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerOptionsSdkTests.cs @@ -57,8 +57,6 @@ public void CreateLoggerProviderBuilderExtensionPointsTest() .ConfigureServices(services => { services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton, CustomProcessor>(); services.Configure(o => { optionsConfigureInvocations++; @@ -108,7 +106,7 @@ public void CreateLoggerProviderBuilderExtensionPointsTest() current = current.Next; } - Assert.Equal(3, count); + Assert.Equal(2, count); } private sealed class TestClass1 diff --git a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs index 674e63eaef5..d4c9c492900 100644 --- a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs +++ b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggerProviderTests.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using OpenTelemetry.Exporter; using OpenTelemetry.Resources; using Xunit; @@ -86,20 +87,20 @@ public void ForceFlushTest() [Fact] public void ThreadStaticPoolUsedByProviderTests() { - using var provider1 = new OpenTelemetryLoggerProvider(new OpenTelemetryLoggerOptions()); + using var provider1 = new OpenTelemetryLoggerProvider(); Assert.Equal(LogRecordThreadStaticPool.Instance, provider1.LogRecordPool); - var options = new OpenTelemetryLoggerOptions(); - options.AddProcessor(new SimpleLogRecordExportProcessor(new NoopExporter())); - - using var provider2 = new OpenTelemetryLoggerProvider(options); + using var provider2 = Sdk.CreateLoggerProviderBuilder() + .AddProcessor(new SimpleLogRecordExportProcessor(new NoopExporter())) + .Build(); Assert.Equal(LogRecordThreadStaticPool.Instance, provider2.LogRecordPool); - options.AddProcessor(new SimpleLogRecordExportProcessor(new NoopExporter())); - - using var provider3 = new OpenTelemetryLoggerProvider(options); + using var provider3 = Sdk.CreateLoggerProviderBuilder() + .AddProcessor(new SimpleLogRecordExportProcessor(new NoopExporter())) + .AddProcessor(new SimpleLogRecordExportProcessor(new NoopExporter())) + .Build(); Assert.Equal(LogRecordThreadStaticPool.Instance, provider3.LogRecordPool); } @@ -107,30 +108,27 @@ public void ThreadStaticPoolUsedByProviderTests() [Fact] public void SharedPoolUsedByProviderTests() { - var options = new OpenTelemetryLoggerOptions(); - options.AddProcessor(new BatchLogRecordExportProcessor(new NoopExporter())); - - using var provider1 = new OpenTelemetryLoggerProvider(options); + using var provider1 = Sdk.CreateLoggerProviderBuilder() + .AddProcessor(new BatchLogRecordExportProcessor(new NoopExporter())) + .Build(); Assert.Equal(LogRecordSharedPool.Current, provider1.LogRecordPool); - options = new OpenTelemetryLoggerOptions(); - options.AddProcessor(new SimpleLogRecordExportProcessor(new NoopExporter())); - options.AddProcessor(new BatchLogRecordExportProcessor(new NoopExporter())); - - using var provider2 = new OpenTelemetryLoggerProvider(options); + using var provider2 = Sdk.CreateLoggerProviderBuilder() + .AddProcessor(new SimpleLogRecordExportProcessor(new NoopExporter())) + .AddProcessor(new BatchLogRecordExportProcessor(new NoopExporter())) + .Build(); Assert.Equal(LogRecordSharedPool.Current, provider2.LogRecordPool); - options = new OpenTelemetryLoggerOptions(); - options.AddProcessor(new SimpleLogRecordExportProcessor(new NoopExporter())); - options.AddProcessor(new CompositeProcessor(new BaseProcessor[] - { - new SimpleLogRecordExportProcessor(new NoopExporter()), - new BatchLogRecordExportProcessor(new NoopExporter()), - })); - - using var provider3 = new OpenTelemetryLoggerProvider(options); + using var provider3 = Sdk.CreateLoggerProviderBuilder() + .AddProcessor(new SimpleLogRecordExportProcessor(new NoopExporter())) + .AddProcessor(new CompositeProcessor(new BaseProcessor[] + { + new SimpleLogRecordExportProcessor(new NoopExporter()), + new BatchLogRecordExportProcessor(new NoopExporter()), + })) + .Build(); Assert.Equal(LogRecordSharedPool.Current, provider3.LogRecordPool); } diff --git a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggingExtensionsTests.cs b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggingExtensionsTests.cs index f4553728681..0d141abd4ad 100644 --- a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggingExtensionsTests.cs +++ b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggingExtensionsTests.cs @@ -16,7 +16,6 @@ #nullable enable -using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -121,19 +120,35 @@ void OptionsCallback(OpenTelemetryLoggerOptions options) } [Fact] - public void LoggingBuilderAddOpenTelemetryMultipleBuildersThrows() + public void LoggingBuilderAddOpenTelemetryMultipleBuildersTest() { var serviceCollection = new ServiceCollection(); + OpenTelemetryLoggerProvider? provider = null; + serviceCollection.AddLogging(configure => { - configure.AddOpenTelemetry(optiosn => { }); - configure.AddOpenTelemetry(optiosn => { }); + configure.AddOpenTelemetry(options + => options.ConfigureResource( + r => r.AddAttributes(new Dictionary() { ["key1"] = "value1" }))); + configure.AddOpenTelemetry(options + => options.ConfigureResource( + r => r.AddAttributes(new Dictionary() { ["key2"] = "value2" }))); + + configure.AddOpenTelemetry(options + => options.ConfigureProvider((sp, p) => provider = p)); }); using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider(); - Assert.Throws(() => serviceProvider.GetService()); + var loggerFactory = serviceProvider.GetService(); + + Assert.NotNull(loggerFactory); + + Assert.NotNull(provider); + + Assert.Contains(provider!.Resource.Attributes, kvp => kvp.Key == "key1" && (string)kvp.Value == "value1"); + Assert.Contains(provider!.Resource.Attributes, kvp => kvp.Key == "key2" && (string)kvp.Value == "value2"); } [Fact] @@ -271,7 +286,7 @@ public void LoggingBuilderAddOpenTelemetryProcessorThroughDependencyTest() { var loggerFactory = serviceProvider.GetRequiredService(); - customProcessor = serviceProvider.GetRequiredService>() as CustomProcessor; + customProcessor = serviceProvider.GetRequiredService(); Assert.NotNull(customProcessor); @@ -319,28 +334,6 @@ public void LoggingBuilderAddOpenTelemetryConfigureCallbackTest() Assert.NotNull(customProcessor?.TestClass); } - [Fact] - public void LoggingBuilderAddOpenTelemetryExternalRegistrationTest() - { - CustomProcessor.InstanceCount = 0; - - var services = new ServiceCollection(); - - services.AddSingleton>(sp => new CustomProcessor()); - services.AddSingleton>(sp => new CustomProcessor()); - - services.AddLogging(configure => - { - configure.AddOpenTelemetry(); - }); - - using var serviceProvider = services.BuildServiceProvider(); - - var loggerFactory = serviceProvider.GetRequiredService(); - - Assert.Equal(2, CustomProcessor.InstanceCount); - } - [Fact] public void LoggingBuilderAddOpenTelemetryOptionsOrderingTest() { @@ -478,21 +471,83 @@ public void LoggingBuilderAddOpenTelemetryResourceTest() } [Fact] - public void LoggingBuilderAddOpenTelemetryDetachedConfigurationTest() + public void LoggingBuilderAddOpenTelemetryAddExporterTest() { - int configurationInvocations = 0; + var builder = Sdk.CreateLoggerProviderBuilder(); - var services = new ServiceCollection(); + builder.AddExporter(ExportProcessorType.Simple, new CustomExporter()); + builder.AddExporter(ExportProcessorType.Batch); - services.AddLogging(configure => configure.AddOpenTelemetry()); + using var provider = builder.Build(); - services.AddSingleton>((sp, provider) => configurationInvocations++); + Assert.NotNull(provider); - using var serviceProvider = services.BuildServiceProvider(); + var processor = provider.Processor as CompositeProcessor; - var loggerFactory = serviceProvider.GetRequiredService(); + Assert.NotNull(processor); + + var firstProcessor = processor!.Head.Value; + var secondProcessor = processor.Head.Next?.Value; + + Assert.True(firstProcessor is SimpleLogRecordExportProcessor simpleProcessor && simpleProcessor.Exporter is CustomExporter); + Assert.True(secondProcessor is BatchLogRecordExportProcessor batchProcessor && batchProcessor.Exporter is CustomExporter); + } + + [Fact] + public void LoggingBuilderAddOpenTelemetryAddExporterWithOptionsTest() + { + int optionsInvocations = 0; + + var builder = Sdk.CreateLoggerProviderBuilder(); + + builder.ConfigureServices(services => + { + services.Configure(options => + { + // Note: This is testing options integration + + optionsInvocations++; + + options.MaxExportBatchSize = 18; + }); + }); + + builder.AddExporter( + ExportProcessorType.Simple, + new CustomExporter(), + options => + { + // Note: Options delegate isn't invoked for simple processor type + Assert.True(false); + }); + builder.AddExporter( + ExportProcessorType.Batch, + options => + { + optionsInvocations++; - Assert.Equal(1, configurationInvocations); + Assert.Equal(18, options.BatchExportProcessorOptions.MaxExportBatchSize); + + options.BatchExportProcessorOptions.MaxExportBatchSize = 100; + }); + + using var provider = builder.Build(); + + Assert.NotNull(provider); + + Assert.Equal(2, optionsInvocations); + + var processor = provider.Processor as CompositeProcessor; + + Assert.NotNull(processor); + + var firstProcessor = processor!.Head.Value; + var secondProcessor = processor.Head.Next?.Value; + + Assert.True(firstProcessor is SimpleLogRecordExportProcessor simpleProcessor && simpleProcessor.Exporter is CustomExporter); + Assert.True(secondProcessor is BatchLogRecordExportProcessor batchProcessor + && batchProcessor.Exporter is CustomExporter + && batchProcessor.MaxExportBatchSize == 100); } private sealed class WrappedOpenTelemetryLoggerProvider : OpenTelemetryLoggerProvider @@ -531,6 +586,14 @@ protected override void Dispose(bool disposing) } } + private sealed class CustomExporter : BaseExporter + { + public override ExportResult Export(in Batch batch) + { + return ExportResult.Success; + } + } + private sealed class TestClass { }