diff --git a/docs/logs/extending-the-sdk/LoggerExtensions.cs b/docs/logs/extending-the-sdk/LoggerExtensions.cs deleted file mode 100644 index 7476d833334..00000000000 --- a/docs/logs/extending-the-sdk/LoggerExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -using OpenTelemetry; -using OpenTelemetry.Logs; - -internal static class LoggerExtensions -{ - public static OpenTelemetryLoggerOptions AddMyExporter(this OpenTelemetryLoggerOptions options) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return options.AddProcessor(new BatchLogRecordExportProcessor(new MyExporter())); - } -} diff --git a/docs/logs/extending-the-sdk/MyExporterExtensions.cs b/docs/logs/extending-the-sdk/MyExporterExtensions.cs new file mode 100644 index 00000000000..d257f8d920b --- /dev/null +++ b/docs/logs/extending-the-sdk/MyExporterExtensions.cs @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.Logs; + +internal static class MyExporterExtensions +{ + public static LoggerProviderBuilder AddMyExporter( + this LoggerProviderBuilder builder) + => AddMyExporter(builder, name: null); + + public static LoggerProviderBuilder AddMyExporter( + this LoggerProviderBuilder builder, + string? name) + { + return builder.AddBatchExportProcessor( + name, + new MyExporter()); + } + + public static OpenTelemetryLoggerOptions AddMyExporter( + this OpenTelemetryLoggerOptions options) + => AddMyExporter(options, name: null); + + public static OpenTelemetryLoggerOptions AddMyExporter( + this OpenTelemetryLoggerOptions options, + string? name) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + ((IDeferredLoggerProviderBuilder)options).Configure( + (sp, builder) => builder.AddBatchExportProcessor(name, new MyExporter())); + + return options; + } +} diff --git a/docs/logs/extending-the-sdk/README.md b/docs/logs/extending-the-sdk/README.md index 55ea13dfaf4..0eeacc528fc 100644 --- a/docs/logs/extending-the-sdk/README.md +++ b/docs/logs/extending-the-sdk/README.md @@ -53,8 +53,10 @@ A demo exporter which simply writes log records to the console is shown [here](./MyExporter.cs). Apart from the exporter itself, you should also provide extension methods as -shown [here](./LoggerExtensions.cs). This allows users to add the Exporter to -the `OpenTelemetryLoggerOptions` as shown in the example [here](./Program.cs). +shown [here](./MyExporterExtensions.cs). This allows users to add the exporter +to the `OpenTelemetryLoggerOptions` (as shown in the example +[here](./Program.cs)) or to a `LoggerProviderBuilder` using the `WithLogging` +extension in `OpenTelemetry.Extensions.Hosting`. ## Processor @@ -64,6 +66,11 @@ OpenTelemetry .NET SDK has provided the following built-in processors: * [CompositeProcessor<T>](../../../src/OpenTelemetry/CompositeProcessor.cs) * [SimpleExportProcessor<T>](../../../src/OpenTelemetry/SimpleExportProcessor.cs) +> [!NOTE] +> As of `1.10.0` it is recommended to use the `LoggerProviderBuilder` +> `AddBatchExportProcessor` or `AddSimpleExportProcessor` helper extension +> methods to create batch and/or simple processors. + Custom processors can be implemented to cover more scenarios: * Processors should inherit from `OpenTelemetry.BaseProcessor` (which diff --git a/docs/trace/customizing-the-sdk/README.md b/docs/trace/customizing-the-sdk/README.md index d78ed1cd569..e6de7f4e6d1 100644 --- a/docs/trace/customizing-the-sdk/README.md +++ b/docs/trace/customizing-the-sdk/README.md @@ -253,18 +253,32 @@ writing custom processors. #### Exporter Configuration -The snippet below shows how to add export processors to the provider before it +The snippets below shows how to add export processors to the provider before it is built. -```csharp -using OpenTelemetry; -using OpenTelemetry.Trace; +* Using 1.10.0 or newer -var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddProcessor(new BatchActivityExportProcessor(new MyExporter1())) - .AddProcessor(new SimpleActivityExportProcessor(new MyExporter2())) - .Build(); -``` + ```csharp + using OpenTelemetry; + using OpenTelemetry.Trace; + + var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddBatchExportProcessor(new MyExporter1()) + .AddSimpleExportProcessor(new MyExporter2()) + .Build(); + ``` + +* Using 1.9.0 or older + + ```csharp + using OpenTelemetry; + using OpenTelemetry.Trace; + + var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddProcessor(new BatchActivityExportProcessor(new MyExporter1())) + .AddProcessor(new SimpleActivityExportProcessor(new MyExporter2())) + .Build(); + ``` It is also common for exporters to provide their own extensions to simplify registration. The snippet below shows how to add the diff --git a/docs/trace/extending-the-sdk/MyExporterExtensions.cs b/docs/trace/extending-the-sdk/MyExporterExtensions.cs index b317591fc5f..43306605790 100644 --- a/docs/trace/extending-the-sdk/MyExporterExtensions.cs +++ b/docs/trace/extending-the-sdk/MyExporterExtensions.cs @@ -1,18 +1,20 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using OpenTelemetry; using OpenTelemetry.Trace; internal static class MyExporterExtensions { - public static TracerProviderBuilder AddMyExporter(this TracerProviderBuilder builder) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } + public static TracerProviderBuilder AddMyExporter( + this TracerProviderBuilder builder) + => AddMyExporter(builder, name: null); - return builder.AddProcessor(new BatchActivityExportProcessor(new MyExporter())); + public static TracerProviderBuilder AddMyExporter( + this TracerProviderBuilder builder, + string? name) + { + return builder.AddBatchExportProcessor( + name, + new MyExporter()); } } diff --git a/docs/trace/extending-the-sdk/README.md b/docs/trace/extending-the-sdk/README.md index 00f72ddec09..d6e46894702 100644 --- a/docs/trace/extending-the-sdk/README.md +++ b/docs/trace/extending-the-sdk/README.md @@ -244,6 +244,11 @@ OpenTelemetry .NET SDK has provided the following built-in processors: * [CompositeProcessor<T>](../../../src/OpenTelemetry/CompositeProcessor.cs) * [SimpleExportProcessor<T>](../../../src/OpenTelemetry/SimpleExportProcessor.cs) +> [!NOTE] +> As of `1.10.0` it is recommended to use the `TracerProviderBuilder` +> `AddBatchExportProcessor` or `AddSimpleExportProcessor` helper extension +> methods to create batch and/or simple processors. + Custom processors can be implemented to cover more scenarios: * Processors should inherit from `OpenTelemetry.BaseProcessor` (which diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.Console/ConsoleExporterHelperExtensions.cs index b79aa0d9ed9..8479c80fcb2 100644 --- a/src/OpenTelemetry.Exporter.Console/ConsoleExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.Console/ConsoleExporterHelperExtensions.cs @@ -48,11 +48,13 @@ public static TracerProviderBuilder AddConsoleExporter( builder.ConfigureServices(services => services.Configure(name, configure)); } - return builder.AddProcessor(sp => - { - var options = sp.GetRequiredService>().Get(name); - - return new SimpleActivityExportProcessor(new ConsoleActivityExporter(options)); - }); + return builder.AddSimpleExportProcessor( + name, + static (sp, name) => + { + var options = sp.GetRequiredService>().Get(name); + + return new ConsoleActivityExporter(options); + }); } } diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs b/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs index 80c767343b7..bd357182764 100644 --- a/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs +++ b/src/OpenTelemetry.Exporter.Console/ConsoleExporterLoggingExtensions.cs @@ -73,14 +73,17 @@ public static LoggerProviderBuilder AddConsoleExporter( if (configure != null) { - loggerProviderBuilder.ConfigureServices(services => services.Configure(name, configure)); + loggerProviderBuilder.ConfigureServices( + services => services.Configure(name, configure)); } - return loggerProviderBuilder.AddProcessor(sp => - { - var options = sp.GetRequiredService>().Get(name); + return loggerProviderBuilder.AddSimpleExportProcessor( + name, + static (sp, name) => + { + var options = sp.GetRequiredService>().Get(name); - return new SimpleLogRecordExportProcessor(new ConsoleLogRecordExporter(options)); - }); + return new ConsoleLogRecordExporter(options); + }); } } diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterHelperExtensions.cs index 3940a846bc3..475052dfe61 100644 --- a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterHelperExtensions.cs @@ -20,6 +20,7 @@ public static TracerProviderBuilder AddInMemoryExporter(this TracerProviderBuild Guard.ThrowIfNull(builder); Guard.ThrowIfNull(exportedItems); - return builder.AddProcessor(new SimpleActivityExportProcessor(new InMemoryExporter(exportedItems))); + return builder.AddSimpleExportProcessor( + new InMemoryExporter(exportedItems)); } } diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterLoggingExtensions.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterLoggingExtensions.cs index 19b2079921e..dfd0bc1a4b1 100644 --- a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterLoggingExtensions.cs +++ b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterLoggingExtensions.cs @@ -24,8 +24,10 @@ public static OpenTelemetryLoggerOptions AddInMemoryExporter( var logExporter = BuildExporter(exportedItems); - return loggerOptions.AddProcessor( - new SimpleLogRecordExportProcessor(logExporter)); + ((IDeferredLoggerProviderBuilder)loggerOptions).Configure( + (sp, builder) => builder.AddSimpleExportProcessor(logExporter)); + + return loggerOptions; } /// @@ -43,8 +45,7 @@ public static LoggerProviderBuilder AddInMemoryExporter( var logExporter = BuildExporter(exportedItems); - return loggerProviderBuilder.AddProcessor( - new SimpleLogRecordExportProcessor(logExporter)); + return loggerProviderBuilder.AddSimpleExportProcessor(logExporter); } private static InMemoryExporter BuildExporter(ICollection exportedItems) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilder.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilder.cs index e20062b0e9e..70ddfd6527f 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilder.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilder.cs @@ -200,17 +200,19 @@ there but that may change in the future so it is handled { var builderOptions = GetBuilderOptionsAndValidateRegistrations(sp, name!); - var processor = OtlpLogExporterHelperExtensions.BuildOtlpLogExporter( + var processorOptions = builderOptions.LogRecordExportProcessorOptions + ?? throw new InvalidOperationException("LogRecordExportProcessorOptions were missing with logging enabled"); + + OtlpLogExporterHelperExtensions.AddOtlpLogExporter( + name, sp, + logging, builderOptions.LoggingOptionsInstance.ApplyDefaults(builderOptions.DefaultOptionsInstance), - builderOptions.LogRecordExportProcessorOptions ?? throw new InvalidOperationException("LogRecordExportProcessorOptions were missing with logging enabled"), builderOptions.SdkLimitOptions, builderOptions.ExperimentalOptions, + processorOptions.ExportProcessorType, + processorPipelineWeight: DefaultProcessorPipelineWeight, skipUseOtlpExporterRegistrationCheck: true); - - processor.PipelineWeight = DefaultProcessorPipelineWeight; - - logging.AddProcessor(processor); }); services!.ConfigureOpenTelemetryMeterProvider( @@ -232,20 +234,19 @@ there but that may change in the future so it is handled { var builderOptions = GetBuilderOptionsAndValidateRegistrations(sp, name!); - var processorOptions = builderOptions.ActivityExportProcessorOptions ?? throw new InvalidOperationException("ActivityExportProcessorOptions were missing with tracing enabled"); + var processorOptions = builderOptions.ActivityExportProcessorOptions + ?? throw new InvalidOperationException("ActivityExportProcessorOptions were missing with tracing enabled"); - var processor = OtlpTraceExporterHelperExtensions.BuildOtlpExporterProcessor( + OtlpTraceExporterHelperExtensions.AddOtlpTraceExporter( + name, sp, + tracing, builderOptions.TracingOptionsInstance.ApplyDefaults(builderOptions.DefaultOptionsInstance), builderOptions.SdkLimitOptions, builderOptions.ExperimentalOptions, processorOptions.ExportProcessorType, - processorOptions.BatchExportProcessorOptions, + processorPipelineWeight: DefaultProcessorPipelineWeight, skipUseOtlpExporterRegistrationCheck: true); - - processor.PipelineWeight = DefaultProcessorPipelineWeight; - - tracing.AddProcessor(processor); }); static OtlpExporterBuilderOptions GetBuilderOptionsAndValidateRegistrations(IServiceProvider sp, string name) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilderOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilderOptions.cs index 7d9786bb040..27f0b27a3ac 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilderOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OtlpExporterBuilderOptions.cs @@ -41,15 +41,15 @@ internal OtlpExporterBuilderOptions( this.MetricReaderOptions = metricReaderOptions; this.ActivityExportProcessorOptions = activityExportProcessorOptions; - var defaultBatchOptions = this.ActivityExportProcessorOptions!.BatchExportProcessorOptions; + var defaultOptions = this.ActivityExportProcessorOptions!; - this.DefaultOptionsInstance = new OtlpExporterOptions(configuration!, OtlpExporterOptionsConfigurationType.Default, defaultBatchOptions); + this.DefaultOptionsInstance = new OtlpExporterOptions(configuration!, OtlpExporterOptionsConfigurationType.Default, defaultOptions); - this.LoggingOptionsInstance = new OtlpExporterOptions(configuration!, OtlpExporterOptionsConfigurationType.Logs, defaultBatchOptions); + this.LoggingOptionsInstance = new OtlpExporterOptions(configuration!, OtlpExporterOptionsConfigurationType.Logs, defaultOptions); - this.MetricsOptionsInstance = new OtlpExporterOptions(configuration!, OtlpExporterOptionsConfigurationType.Metrics, defaultBatchOptions); + this.MetricsOptionsInstance = new OtlpExporterOptions(configuration!, OtlpExporterOptionsConfigurationType.Metrics, defaultOptions); - this.TracingOptionsInstance = new OtlpExporterOptions(configuration!, OtlpExporterOptionsConfigurationType.Traces, defaultBatchOptions); + this.TracingOptionsInstance = new OtlpExporterOptions(configuration!, OtlpExporterOptionsConfigurationType.Traces, defaultOptions); } public IOtlpExporterOptions DefaultOptions => this.DefaultOptionsInstance; diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs index 355ab376743..c9076909a57 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs @@ -53,16 +53,16 @@ internal OtlpExporterOptions( : this( configuration: new ConfigurationBuilder().AddEnvironmentVariables().Build(), configurationType, - defaultBatchOptions: new()) + defaultOptions: new()) { } internal OtlpExporterOptions( IConfiguration configuration, OtlpExporterOptionsConfigurationType configurationType, - BatchExportActivityProcessorOptions defaultBatchOptions) + ActivityExportProcessorOptions defaultOptions) { - Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null"); + Debug.Assert(defaultOptions != null, "defaultOptions was null"); this.ApplyConfiguration(configuration, configurationType); @@ -74,7 +74,8 @@ internal OtlpExporterOptions( }; }; - this.BatchExportProcessorOptions = defaultBatchOptions!; + this.ExportProcessorType = defaultOptions!.ExportProcessorType; + this.BatchExportProcessorOptions = defaultOptions.BatchExportProcessorOptions; } /// @@ -165,7 +166,7 @@ internal static OtlpExporterOptions CreateOtlpExporterOptions( => new( configuration, OtlpExporterOptionsConfigurationType.Default, - serviceProvider.GetRequiredService>().Get(name)); + serviceProvider.GetRequiredService>().Get(name)); internal void ApplyConfigurationUsingSpecificationEnvVars( IConfiguration configuration, diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs index 42faf425356..1b220db803f 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs @@ -56,7 +56,7 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter( var finalOptionsName = name ?? Options.DefaultName; - return loggerOptions.AddProcessor(sp => + ((IDeferredLoggerProviderBuilder)loggerOptions).Configure((sp, builder) => { var exporterOptions = GetOptions(sp, name, finalOptionsName, OtlpExporterOptions.CreateOtlpExporterOptions); @@ -64,13 +64,17 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter( configure?.Invoke(exporterOptions); - return BuildOtlpLogExporter( + AddOtlpLogExporter( + finalOptionsName, sp, + builder, exporterOptions, - processorOptions, GetOptions(sp, Options.DefaultName, Options.DefaultName, (sp, c, n) => new SdkLimitOptions(c)), - GetOptions(sp, name, finalOptionsName, (sp, c, n) => new ExperimentalOptions(c))); + GetOptions(sp, name, finalOptionsName, (sp, c, n) => new ExperimentalOptions(c)), + processorOptions.ExportProcessorType); }); + + return loggerOptions; } /// @@ -102,7 +106,7 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter( var finalOptionsName = name ?? Options.DefaultName; - return loggerOptions.AddProcessor(sp => + ((IDeferredLoggerProviderBuilder)loggerOptions).Configure((sp, builder) => { var exporterOptions = GetOptions(sp, name, finalOptionsName, OtlpExporterOptions.CreateOtlpExporterOptions); @@ -110,13 +114,17 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter( configureExporterAndProcessor?.Invoke(exporterOptions, processorOptions); - return BuildOtlpLogExporter( + AddOtlpLogExporter( + finalOptionsName, sp, + builder, exporterOptions, - processorOptions, GetOptions(sp, Options.DefaultName, Options.DefaultName, (sp, c, n) => new SdkLimitOptions(c)), - GetOptions(sp, name, finalOptionsName, (sp, c, n) => new ExperimentalOptions(c))); + GetOptions(sp, name, finalOptionsName, (sp, c, n) => new ExperimentalOptions(c)), + processorOptions.ExportProcessorType); }); + + return loggerOptions; } /// @@ -173,7 +181,7 @@ public static LoggerProviderBuilder AddOtlpExporter( services.AddOtlpExporterLoggingServices(); }); - return builder.AddProcessor(sp => + return builder.ConfigureBuilder((sp, builder) => { OtlpExporterOptions exporterOptions; @@ -202,12 +210,14 @@ public static LoggerProviderBuilder AddOtlpExporter( // instance. var sdkLimitOptions = sp.GetRequiredService>().CurrentValue; - return BuildOtlpLogExporter( + AddOtlpLogExporter( + finalOptionsName, sp, + builder, exporterOptions, - sp.GetRequiredService>().Get(finalOptionsName), sdkLimitOptions, - sp.GetRequiredService>().Get(finalOptionsName)); + sp.GetRequiredService>().Get(finalOptionsName), + sp.GetRequiredService>().Get(finalOptionsName).ExportProcessorType); }); } @@ -229,7 +239,7 @@ public static LoggerProviderBuilder AddOtlpExporter( builder.ConfigureServices(services => services.AddOtlpExporterLoggingServices()); - return builder.AddProcessor(sp => + return builder.ConfigureBuilder((sp, builder) => { OtlpExporterOptions exporterOptions; @@ -260,27 +270,32 @@ public static LoggerProviderBuilder AddOtlpExporter( // instance. var sdkLimitOptions = sp.GetRequiredService>().CurrentValue; - return BuildOtlpLogExporter( + AddOtlpLogExporter( + finalOptionsName, sp, + builder, exporterOptions, - processorOptions, sdkLimitOptions, - sp.GetRequiredService>().Get(finalOptionsName)); + sp.GetRequiredService>().Get(finalOptionsName), + processorOptions.ExportProcessorType); }); } - internal static BaseProcessor BuildOtlpLogExporter( + internal static void AddOtlpLogExporter( + string? name, IServiceProvider serviceProvider, + LoggerProviderBuilder builder, OtlpExporterOptions exporterOptions, - LogRecordExportProcessorOptions processorOptions, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, + ExportProcessorType exportProcessorType, + int processorPipelineWeight = 0, bool skipUseOtlpExporterRegistrationCheck = false, Func, BaseExporter>? configureExporterInstance = null) { Debug.Assert(serviceProvider != null, "serviceProvider was null"); + Debug.Assert(builder != null, "builder was null"); Debug.Assert(exporterOptions != null, "exporterOptions was null"); - Debug.Assert(processorOptions != null, "processorOptions was null"); Debug.Assert(sdkLimitOptions != null, "sdkLimitOptions was null"); Debug.Assert(experimentalOptions != null, "experimentalOptions was null"); @@ -315,20 +330,19 @@ internal static BaseProcessor BuildOtlpLogExporter( otlpExporter = configureExporterInstance(otlpExporter); } - if (processorOptions!.ExportProcessorType == ExportProcessorType.Simple) + if (exportProcessorType == ExportProcessorType.Simple) { - return new SimpleLogRecordExportProcessor(otlpExporter); + builder!.AddSimpleExportProcessor( + name, + (sp, name) => otlpExporter, + processorPipelineWeight); } else { - var batchOptions = processorOptions.BatchExportProcessorOptions; - - return new BatchLogRecordExportProcessor( - otlpExporter, - batchOptions.MaxQueueSize, - batchOptions.ScheduledDelayMilliseconds, - batchOptions.ExporterTimeoutMilliseconds, - batchOptions.MaxExportBatchSize); + builder!.AddBatchExportProcessor( + name, + (sp, name) => otlpExporter, + processorPipelineWeight); } } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs index 3a18b3da423..335b47269f9 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs @@ -60,7 +60,7 @@ public static TracerProviderBuilder AddOtlpExporter( services.AddOtlpExporterTracingServices(); }); - return builder.AddProcessor(sp => + return builder.ConfigureBuilder((sp, builder) => { OtlpExporterOptions exporterOptions; @@ -89,45 +89,36 @@ public static TracerProviderBuilder AddOtlpExporter( // instance. var sdkLimitOptions = sp.GetRequiredService>().CurrentValue; - return BuildOtlpExporterProcessor( + SyncExporterOptionsToDefaults(sp, finalOptionsName, exporterOptions); + + AddOtlpTraceExporter( + finalOptionsName, sp, + builder, exporterOptions, sdkLimitOptions, - sp.GetRequiredService>().Get(finalOptionsName)); + sp.GetRequiredService>().Get(finalOptionsName), + exporterOptions.ExportProcessorType); }); } - internal static BaseProcessor BuildOtlpExporterProcessor( - IServiceProvider serviceProvider, - OtlpExporterOptions exporterOptions, - SdkLimitOptions sdkLimitOptions, - ExperimentalOptions experimentalOptions, - Func, BaseExporter>? configureExporterInstance = null) - => BuildOtlpExporterProcessor( - serviceProvider, - exporterOptions, - sdkLimitOptions, - experimentalOptions, - exporterOptions.ExportProcessorType, - exporterOptions.BatchExportProcessorOptions ?? new BatchExportActivityProcessorOptions(), - skipUseOtlpExporterRegistrationCheck: false, - configureExporterInstance: configureExporterInstance); - - internal static BaseProcessor BuildOtlpExporterProcessor( + internal static void AddOtlpTraceExporter( + string? name, IServiceProvider serviceProvider, + TracerProviderBuilder builder, OtlpExporterOptions exporterOptions, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, ExportProcessorType exportProcessorType, - BatchExportProcessorOptions batchExportProcessorOptions, + int processorPipelineWeight = 0, bool skipUseOtlpExporterRegistrationCheck = false, Func, BaseExporter>? configureExporterInstance = null) { Debug.Assert(serviceProvider != null, "serviceProvider was null"); + Debug.Assert(builder != null, "builder was null"); Debug.Assert(exporterOptions != null, "exporterOptions was null"); Debug.Assert(sdkLimitOptions != null, "sdkLimitOptions was null"); Debug.Assert(experimentalOptions != null, "experimentalOptions was null"); - Debug.Assert(batchExportProcessorOptions != null, "batchExportProcessorOptions was null"); if (!skipUseOtlpExporterRegistrationCheck) { @@ -145,16 +136,46 @@ internal static BaseProcessor BuildOtlpExporterProcessor( if (exportProcessorType == ExportProcessorType.Simple) { - return new SimpleActivityExportProcessor(otlpExporter); + builder!.AddSimpleExportProcessor( + name, + (sp, name) => otlpExporter, + processorPipelineWeight); } else { - return new BatchActivityExportProcessor( - otlpExporter, - batchExportProcessorOptions!.MaxQueueSize, - batchExportProcessorOptions.ScheduledDelayMilliseconds, - batchExportProcessorOptions.ExporterTimeoutMilliseconds, - batchExportProcessorOptions.MaxExportBatchSize); + builder!.AddBatchExportProcessor( + name, + (sp, name) => otlpExporter, + processorPipelineWeight); + } + } + + private static void SyncExporterOptionsToDefaults( + IServiceProvider serviceProvider, + string finalOptionsName, + OtlpExporterOptions exporterOptions) + { + var defaultOptions = serviceProvider.GetRequiredService>() + .Get(finalOptionsName); + + if (exporterOptions.ExportProcessorType != defaultOptions.ExportProcessorType) + { + defaultOptions.ExportProcessorType = exporterOptions.ExportProcessorType; + } + + var defaultBatchOptions = defaultOptions.BatchExportProcessorOptions; + var exporterBatchOptions = exporterOptions.BatchExportProcessorOptions; + if (exporterBatchOptions != null + && exporterBatchOptions != defaultBatchOptions) + { + // Note: By default + // OtlpExporterOptions.BatchExportProcessorOptions + // is set to BatchExportActivityProcessorOptions + // retrieved from DI. But users may change it via + // public setter so this code makes sure any changes + // are reflected on the DI instance so the call to + // AddBatchExportProcessor picks them up. + exporterBatchOptions.ApplyTo(defaultBatchOptions); } } } diff --git a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj index 22b6537a7dd..06afbabfe74 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj +++ b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj @@ -10,15 +10,11 @@ - - - - - - + + diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs index ca858c649ab..6036a2d0792 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterHelperExtensions.cs @@ -4,7 +4,6 @@ #if NETFRAMEWORK using System.Net.Http; #endif -using System.Diagnostics; using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -51,7 +50,7 @@ public static TracerProviderBuilder AddZipkinExporter( name ??= Options.DefaultName; - builder.ConfigureServices(services => + return builder.ConfigureServices(services => { if (configure != null) { @@ -61,25 +60,25 @@ public static TracerProviderBuilder AddZipkinExporter( services.RegisterOptionsFactory( (sp, configuration, name) => new ZipkinExporterOptions( configuration, - sp.GetRequiredService>().Get(name))); - }); - - return builder.AddProcessor(sp => - { - var options = sp.GetRequiredService>().Get(name); + sp.GetRequiredService>().Get(name))); - return BuildZipkinExporterProcessor(builder, options, sp); + services.ConfigureOpenTelemetryTracerProvider( + (sp, builder) => AddZipkinExporter(sp, builder, name)); }); } - private static BaseProcessor BuildZipkinExporterProcessor( + private static void AddZipkinExporter( + IServiceProvider serviceProvider, TracerProviderBuilder builder, - ZipkinExporterOptions options, - IServiceProvider serviceProvider) + string name) { - if (options.HttpClientFactory == ZipkinExporterOptions.DefaultHttpClientFactory) + var exporterOptions = serviceProvider.GetRequiredService>().Get(name); + + SyncExporterOptionsToDefaults(serviceProvider, name, exporterOptions); + + if (exporterOptions.HttpClientFactory == ZipkinExporterOptions.DefaultHttpClientFactory) { - options.HttpClientFactory = () => + exporterOptions.HttpClientFactory = () => { Type httpClientFactoryType = Type.GetType("System.Net.Http.IHttpClientFactory, Microsoft.Extensions.Http", throwOnError: false); if (httpClientFactoryType != null) @@ -104,20 +103,44 @@ private static BaseProcessor BuildZipkinExporterProcessor( }; } - var zipkinExporter = new ZipkinExporter(options); + var zipkinExporter = new ZipkinExporter(exporterOptions); - if (options.ExportProcessorType == ExportProcessorType.Simple) + if (exporterOptions.ExportProcessorType == ExportProcessorType.Simple) { - return new SimpleActivityExportProcessor(zipkinExporter); + builder.AddSimpleExportProcessor(name, zipkinExporter); } else { - return new BatchActivityExportProcessor( - zipkinExporter, - options.BatchExportProcessorOptions.MaxQueueSize, - options.BatchExportProcessorOptions.ScheduledDelayMilliseconds, - options.BatchExportProcessorOptions.ExporterTimeoutMilliseconds, - options.BatchExportProcessorOptions.MaxExportBatchSize); + builder.AddBatchExportProcessor(name, zipkinExporter); + } + } + + private static void SyncExporterOptionsToDefaults( + IServiceProvider serviceProvider, + string name, + ZipkinExporterOptions exporterOptions) + { + var defaultOptions = serviceProvider.GetRequiredService>() + .Get(name); + + if (exporterOptions.ExportProcessorType != defaultOptions.ExportProcessorType) + { + defaultOptions.ExportProcessorType = exporterOptions.ExportProcessorType; + } + + var defaultBatchOptions = defaultOptions.BatchExportProcessorOptions; + var exporterBatchOptions = exporterOptions.BatchExportProcessorOptions; + if (exporterBatchOptions != null + && exporterBatchOptions != defaultBatchOptions) + { + // Note: By default + // ZipkinExporterOptions.BatchExportProcessorOptions is + // set to BatchExportActivityProcessorOptions retrieved + // from DI. But users may change it via public setter so + // this code makes sure any changes are reflected on the + // DI instance so the call to AddBatchExportProcessor + // picks them up. + exporterBatchOptions.ApplyTo(defaultBatchOptions); } } } diff --git a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs index bc94307351d..2ccd9a61fef 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/ZipkinExporterOptions.cs @@ -35,17 +35,18 @@ public ZipkinExporterOptions() internal ZipkinExporterOptions( IConfiguration configuration, - BatchExportActivityProcessorOptions defaultBatchOptions) + ActivityExportProcessorOptions defaultOptions) { Debug.Assert(configuration != null, "configuration was null"); - Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null"); + Debug.Assert(defaultOptions != null, "defaultOptions was null"); if (configuration.TryGetUriValue(ZipkinExporterEventSource.Log, ZipkinEndpointEnvVar, out var endpoint)) { this.Endpoint = endpoint; } - this.BatchExportProcessorOptions = defaultBatchOptions; + this.ExportProcessorType = defaultOptions.ExportProcessorType; + this.BatchExportProcessorOptions = defaultOptions.BatchExportProcessorOptions; } /// diff --git a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt index 7dc29c7de2d..3593da9d519 100644 --- a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt @@ -1,8 +1,30 @@ +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.OpenTelemetrySdk OpenTelemetry.OpenTelemetrySdk.Dispose() -> void OpenTelemetry.OpenTelemetrySdk.LoggerProvider.get -> OpenTelemetry.Logs.LoggerProvider! OpenTelemetry.OpenTelemetrySdk.MeterProvider.get -> OpenTelemetry.Metrics.MeterProvider! OpenTelemetry.OpenTelemetrySdk.TracerProvider.get -> OpenTelemetry.Trace.TracerProvider! OpenTelemetry.OpenTelemetrySdkExtensions +static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddBatchExportProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Logs.LoggerProviderBuilder! +static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddBatchExportProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, string? name, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Logs.LoggerProviderBuilder! +static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddBatchExportProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, string? name, System.Func!>! implementationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder! +static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddBatchExportProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Func!>! implementationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder! +static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddSimpleExportProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Logs.LoggerProviderBuilder! +static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddSimpleExportProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, string? name, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Logs.LoggerProviderBuilder! +static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddSimpleExportProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, string? name, System.Func!>! implementationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder! +static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddSimpleExportProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Func!>! implementationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder! static OpenTelemetry.OpenTelemetrySdk.Create(System.Action! configure) -> OpenTelemetry.OpenTelemetrySdk! static OpenTelemetry.OpenTelemetrySdkExtensions.GetLoggerFactory(this OpenTelemetry.OpenTelemetrySdk! sdk) -> Microsoft.Extensions.Logging.ILoggerFactory! +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddBatchExportProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddBatchExportProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, string? name, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddBatchExportProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, string? name, System.Func!>! implementationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddBatchExportProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func!>! implementationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddSimpleExportProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddSimpleExportProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, string? name, OpenTelemetry.BaseExporter! exporter) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddSimpleExportProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, string? name, System.Func!>! implementationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddSimpleExportProcessor(this OpenTelemetry.Trace.TracerProviderBuilder! tracerProviderBuilder, System.Func!>! implementationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! diff --git a/src/OpenTelemetry/AssemblyInfo.cs b/src/OpenTelemetry/AssemblyInfo.cs index 46c323088a6..df9434b687d 100644 --- a/src/OpenTelemetry/AssemblyInfo.cs +++ b/src/OpenTelemetry/AssemblyInfo.cs @@ -10,6 +10,8 @@ [assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.HttpListener.Tests" + AssemblyInfo.PublicKey)] +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Zipkin" + AssemblyInfo.PublicKey)] +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Zipkin.Tests" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting.Tests" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Tests" + AssemblyInfo.PublicKey)] diff --git a/src/OpenTelemetry/BatchExportProcessorOptions.cs b/src/OpenTelemetry/BatchExportProcessorOptions.cs index 67345e9715c..90ac9abb71e 100644 --- a/src/OpenTelemetry/BatchExportProcessorOptions.cs +++ b/src/OpenTelemetry/BatchExportProcessorOptions.cs @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.Internal; + namespace OpenTelemetry; /// @@ -29,4 +31,22 @@ public class BatchExportProcessorOptions /// Gets or sets the maximum batch size of every export. It must be smaller or equal to MaxQueueLength. The default value is 512. /// public int MaxExportBatchSize { get; set; } = BatchExportProcessor.DefaultMaxExportBatchSize; + + /// + /// Applies the settings for the current instance onto another instance. + /// + /// . + internal void ApplyTo(BatchExportProcessorOptions other) + { + Guard.ThrowIfNull(other); + + if (other != this) + { + other.MaxQueueSize = this.MaxQueueSize; + other.ScheduledDelayMilliseconds = this.ScheduledDelayMilliseconds; + other.ExporterTimeoutMilliseconds = this.ExporterTimeoutMilliseconds; + other.MaxExportBatchSize = this.MaxExportBatchSize; + } + } } diff --git a/src/OpenTelemetry/ConcurrencyModes.cs b/src/OpenTelemetry/ConcurrencyModes.cs new file mode 100644 index 00000000000..f7d7c6da1cd --- /dev/null +++ b/src/OpenTelemetry/ConcurrencyModes.cs @@ -0,0 +1,36 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +namespace OpenTelemetry; + +/// +/// Describes the concurrency mode of an OpenTelemetry component. +/// +[Flags] +public enum ConcurrencyModes : byte +{ + /* + 0 0 0 0 0 0 0 0 + | | | | | | | | + | | | | | | | +--- Reentrant + | | | | | | +----- Multithreaded + | | | | | +------- (reserved) + | | | | +--------- (reserved) + | | | +----------- (reserved) + | | +------------- (reserved) + | +--------------- (reserved) + +----------------- (reserved) + */ + + /// + /// 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, +} diff --git a/src/OpenTelemetry/ConcurrencyModesAttribute.cs b/src/OpenTelemetry/ConcurrencyModesAttribute.cs new file mode 100644 index 00000000000..c3abfb5d71a --- /dev/null +++ b/src/OpenTelemetry/ConcurrencyModesAttribute.cs @@ -0,0 +1,49 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Diagnostics; +using System.Reflection; + +namespace OpenTelemetry; + +/// +/// An attribute for declaring the supported of an OpenTelemetry component. +/// +[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; + + internal static ConcurrencyModes GetConcurrencyModeForExporter( + BaseExporter exporter) + where T : class + { + Debug.Assert(exporter != null, "exporter was null"); + + var concurrencyMode = exporter! + .GetType() + .GetCustomAttribute(inherit: true)?.Supported + ?? ConcurrencyModes.Reentrant; + + if (!concurrencyMode.HasFlag(ConcurrencyModes.Reentrant)) + { + throw new NotSupportedException("Non-reentrant simple export processors are not currently supported."); + } + + return concurrencyMode; + } +} diff --git a/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderExtensions.cs b/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderExtensions.cs index 775e7ecb5a1..29d03d0d9da 100644 --- a/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Logs/Builder/LoggerProviderBuilderExtensions.cs @@ -6,6 +6,7 @@ #endif using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; using OpenTelemetry.Internal; using OpenTelemetry.Resources; @@ -138,6 +139,142 @@ public static LoggerProviderBuilder AddProcessor( return loggerProviderBuilder; } + /// + /// Adds a to the provider for the supplied exporter. + /// + /// . + /// . + /// The supplied for chaining. + public static LoggerProviderBuilder AddBatchExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + BaseExporter exporter) + => AddBatchExportProcessor(loggerProviderBuilder, name: null, exporter); + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// . + /// Optional name which is used when retrieving options. + /// . + /// The supplied for chaining. + public static LoggerProviderBuilder AddBatchExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + string? name, + BaseExporter exporter) + { + Guard.ThrowIfNull(exporter); + + return AddBatchExportProcessor( + loggerProviderBuilder, + name, + implementationFactory: (sp, name) => exporter, + pipelineWeight: 0); + } + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// . + /// Factory function used to create the exporter. + /// The supplied for chaining. + public static LoggerProviderBuilder AddBatchExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + Func> implementationFactory) + { + Guard.ThrowIfNull(implementationFactory); + + return AddBatchExportProcessor( + loggerProviderBuilder, + name: null, + implementationFactory: (sp, name) => implementationFactory(sp), + pipelineWeight: 0); + } + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// . + /// Optional name which is used when retrieving options. + /// Factory function used to create the exporter. + /// The supplied for chaining. + public static LoggerProviderBuilder AddBatchExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + string? name, + Func> implementationFactory) + => AddBatchExportProcessor(loggerProviderBuilder, name, implementationFactory, pipelineWeight: 0); + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// + /// Note: The concurrency behavior of the constructed can be controlled by decorating + /// the exporter with the . + /// + /// . + /// . + /// The supplied for chaining. + public static LoggerProviderBuilder AddSimpleExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + BaseExporter exporter) + => AddSimpleExportProcessor(loggerProviderBuilder, name: null, exporter); + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// + /// . + /// Optional name which is used when retrieving options. + /// . + /// The supplied for chaining. + public static LoggerProviderBuilder AddSimpleExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + string? name, + BaseExporter exporter) + { + Guard.ThrowIfNull(exporter); + + return AddSimpleExportProcessor( + loggerProviderBuilder, + name, + implementationFactory: (sp, name) => exporter, + pipelineWeight: 0); + } + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// + /// . + /// Factory function used to create the exporter. + /// The supplied for chaining. + public static LoggerProviderBuilder AddSimpleExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + Func> implementationFactory) + { + Guard.ThrowIfNull(implementationFactory); + + return AddSimpleExportProcessor( + loggerProviderBuilder, + name: null, + implementationFactory: (sp, name) => implementationFactory(sp), + pipelineWeight: 0); + } + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// + /// . + /// Optional name which is used when retrieving options. + /// Factory function used to create the exporter. + /// The supplied for chaining. + public static LoggerProviderBuilder AddSimpleExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + string? name, + Func> implementationFactory) + => AddSimpleExportProcessor(loggerProviderBuilder, name, implementationFactory, pipelineWeight: 0); + /// /// Run the given actions to initialize the . /// @@ -152,4 +289,43 @@ public static LoggerProvider Build(this LoggerProviderBuilder loggerProviderBuil throw new NotSupportedException($"Build is not supported on '{loggerProviderBuilder?.GetType().FullName ?? "null"}' instances."); } + + internal static LoggerProviderBuilder AddBatchExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + string? name, + Func> implementationFactory, + int pipelineWeight) + { + Guard.ThrowIfNull(implementationFactory); + + return loggerProviderBuilder.AddProcessor(sp => + { + var options = sp.GetRequiredService>().Get(name); + + var exporter = implementationFactory(sp, name) + ?? throw new InvalidOperationException("Implementation factory returned a null instance"); + + return LogRecordExportProcessorFactory.CreateBatchExportProcessor( + exporter, + options.BatchExportProcessorOptions, + pipelineWeight); + }); + } + + internal static LoggerProviderBuilder AddSimpleExportProcessor( + this LoggerProviderBuilder loggerProviderBuilder, + string? name, + Func> implementationFactory, + int pipelineWeight) + { + Guard.ThrowIfNull(implementationFactory); + + return loggerProviderBuilder.AddProcessor(sp => + { + var exporter = implementationFactory(sp, name) + ?? throw new InvalidOperationException("Implementation factory returned a null instance"); + + return LogRecordExportProcessorFactory.CreateSimpleExportProcessor(exporter, pipelineWeight); + }); + } } diff --git a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs index 921fd948ce0..bc232a6df27 100644 --- a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs +++ b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggerOptions.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using System.Diagnostics; +using Microsoft.Extensions.DependencyInjection; using OpenTelemetry.Internal; using OpenTelemetry.Resources; @@ -10,10 +11,25 @@ namespace OpenTelemetry.Logs; /// /// Contains OpenTelemetry logging options. /// -public class OpenTelemetryLoggerOptions +public class OpenTelemetryLoggerOptions : IDeferredLoggerProviderBuilder { internal readonly List>> ProcessorFactories = new(); internal ResourceBuilder? ResourceBuilder; + private readonly LoggerProviderBuilderSdk? innerBuilder; + + /// + /// Initializes a new instance of the class. + /// + public OpenTelemetryLoggerOptions() + { + } + + internal OpenTelemetryLoggerOptions(IServiceProvider serviceProvider) + { + Debug.Assert(serviceProvider != null, "serviceProvider was null"); + + this.innerBuilder = serviceProvider!.GetRequiredService(); + } /// /// Gets or sets a value indicating whether or not formatted log message @@ -87,7 +103,14 @@ public OpenTelemetryLoggerOptions AddProcessor(BaseProcessor processo { Guard.ThrowIfNull(processor); - this.ProcessorFactories.Add(_ => processor); + if (this.innerBuilder != null) + { + this.innerBuilder.AddProcessor(processor); + } + else + { + this.ProcessorFactories.Add(_ => processor); + } return this; } @@ -103,7 +126,14 @@ public OpenTelemetryLoggerOptions AddProcessor( { Guard.ThrowIfNull(implementationFactory); - this.ProcessorFactories.Add(implementationFactory); + if (this.innerBuilder != null) + { + this.innerBuilder.AddProcessor(implementationFactory); + } + else + { + this.ProcessorFactories.Add(implementationFactory); + } return this; } @@ -119,11 +149,29 @@ public OpenTelemetryLoggerOptions SetResourceBuilder(ResourceBuilder resourceBui { Guard.ThrowIfNull(resourceBuilder); - this.ResourceBuilder = resourceBuilder; + if (this.innerBuilder != null) + { + this.innerBuilder.SetResourceBuilder(resourceBuilder); + } + else + { + this.ResourceBuilder = resourceBuilder; + } return this; } + LoggerProviderBuilder IDeferredLoggerProviderBuilder.Configure( + Action configure) + { + Guard.ThrowIfNull(configure); + + var innerBuilder = this.innerBuilder + ?? throw new NotSupportedException("Manually constructed OpenTelemetryLoggerOptions instances cannot be converted to LoggerProviderBuilder instances"); + + return innerBuilder.ConfigureBuilder(configure); + } + internal OpenTelemetryLoggerOptions Copy() { return new() diff --git a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggingExtensions.cs b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggingExtensions.cs index 973096cf7bc..3eccbb50651 100644 --- a/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggingExtensions.cs +++ b/src/OpenTelemetry/Logs/ILogger/OpenTelemetryLoggingExtensions.cs @@ -157,6 +157,9 @@ private static ILoggingBuilder AddOpenTelemetryInternal( */ services.AddOpenTelemetrySharedProviderBuilderServices(); + services.RegisterOptionsFactory( + (sp, config, name) => new OpenTelemetryLoggerOptions(sp)); + if (configureOptions != null) { // Note: Order is important here so that user-supplied delegate diff --git a/src/OpenTelemetry/Logs/Processor/LogRecordExportProcessorFactory.cs b/src/OpenTelemetry/Logs/Processor/LogRecordExportProcessorFactory.cs new file mode 100644 index 00000000000..121b9aa7ca5 --- /dev/null +++ b/src/OpenTelemetry/Logs/Processor/LogRecordExportProcessorFactory.cs @@ -0,0 +1,45 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Logs; + +internal static class LogRecordExportProcessorFactory +{ + public static BaseExportProcessor CreateBatchExportProcessor( + BaseExporter exporter, + BatchExportProcessorOptions options, + int pipelineWeight) + { + Guard.ThrowIfNull(exporter); + Guard.ThrowIfNull(options); + + return new BatchLogRecordExportProcessor( + exporter, + options.MaxQueueSize, + options.ScheduledDelayMilliseconds, + options.ExporterTimeoutMilliseconds, + options.MaxExportBatchSize) + { + PipelineWeight = pipelineWeight, + }; + } + + public static BaseExportProcessor CreateSimpleExportProcessor( + BaseExporter exporter, + int pipelineWeight) + { + Guard.ThrowIfNull(exporter); + + BaseExportProcessor processor = ConcurrencyModesAttribute + .GetConcurrencyModeForExporter(exporter) + .HasFlag(ConcurrencyModes.Multithreaded) + ? new SimpleMultithreadedExportProcessor(exporter) + : new SimpleLogRecordExportProcessor(exporter); + + processor.PipelineWeight = pipelineWeight; + + return processor; + } +} diff --git a/src/OpenTelemetry/SimpleMultithreadedExportProcessor.cs b/src/OpenTelemetry/SimpleMultithreadedExportProcessor.cs new file mode 100644 index 00000000000..acc1832165f --- /dev/null +++ b/src/OpenTelemetry/SimpleMultithreadedExportProcessor.cs @@ -0,0 +1,32 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.Internal; + +namespace OpenTelemetry; + +internal class SimpleMultithreadedExportProcessor : BaseExportProcessor + where T : class +{ + /// + /// Initializes a new instance of the class. + /// + /// Exporter instance. + public SimpleMultithreadedExportProcessor(BaseExporter exporter) + : base(exporter) + { + } + + /// + protected override void OnExport(T data) + { + try + { + this.exporter.Export(new Batch(data)); + } + catch (Exception ex) + { + OpenTelemetrySdkEventSource.Log.SpanProcessorException(nameof(this.OnExport), ex); + } + } +} diff --git a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs index c429dad7b01..47eaecc3b66 100644 --- a/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry/Trace/Builder/TracerProviderBuilderExtensions.cs @@ -7,6 +7,7 @@ #endif using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; using OpenTelemetry.Internal; using OpenTelemetry.Resources; @@ -237,6 +238,142 @@ public static TracerProviderBuilder AddProcessor( return tracerProviderBuilder; } + /// + /// Adds a to the provider for the supplied exporter. + /// + /// . + /// . + /// The supplied for chaining. + public static TracerProviderBuilder AddBatchExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + BaseExporter exporter) + => AddBatchExportProcessor(tracerProviderBuilder, name: null, exporter); + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// . + /// Optional name which is used when retrieving options. + /// . + /// The supplied for chaining. + public static TracerProviderBuilder AddBatchExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + string? name, + BaseExporter exporter) + { + Guard.ThrowIfNull(exporter); + + return AddBatchExportProcessor( + tracerProviderBuilder, + name, + implementationFactory: (sp, name) => exporter, + pipelineWeight: 0); + } + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// . + /// Factory function used to create the exporter. + /// The supplied for chaining. + public static TracerProviderBuilder AddBatchExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + Func> implementationFactory) + { + Guard.ThrowIfNull(implementationFactory); + + return AddBatchExportProcessor( + tracerProviderBuilder, + name: null, + implementationFactory: (sp, name) => implementationFactory(sp), + pipelineWeight: 0); + } + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// . + /// Optional name which is used when retrieving options. + /// Factory function used to create the exporter. + /// The supplied for chaining. + public static TracerProviderBuilder AddBatchExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + string? name, + Func> implementationFactory) + => AddBatchExportProcessor(tracerProviderBuilder, name, implementationFactory, pipelineWeight: 0); + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// + /// Note: The concurrency behavior of the constructed can be controlled by decorating + /// the exporter with the . + /// + /// . + /// . + /// The supplied for chaining. + public static TracerProviderBuilder AddSimpleExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + BaseExporter exporter) + => AddSimpleExportProcessor(tracerProviderBuilder, name: null, exporter); + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// + /// . + /// Optional name which is used when retrieving options. + /// . + /// The supplied for chaining. + public static TracerProviderBuilder AddSimpleExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + string? name, + BaseExporter exporter) + { + Guard.ThrowIfNull(exporter); + + return AddSimpleExportProcessor( + tracerProviderBuilder, + name, + implementationFactory: (sp, name) => exporter, + pipelineWeight: 0); + } + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// + /// . + /// Factory function used to create the exporter. + /// The supplied for chaining. + public static TracerProviderBuilder AddSimpleExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + Func> implementationFactory) + { + Guard.ThrowIfNull(implementationFactory); + + return AddSimpleExportProcessor( + tracerProviderBuilder, + name: null, + implementationFactory: (sp, name) => implementationFactory(sp), + pipelineWeight: 0); + } + + /// + /// Adds a to the provider for the supplied exporter. + /// + /// + /// . + /// Optional name which is used when retrieving options. + /// Factory function used to create the exporter. + /// The supplied for chaining. + public static TracerProviderBuilder AddSimpleExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + string? name, + Func> implementationFactory) + => AddSimpleExportProcessor(tracerProviderBuilder, name, implementationFactory, pipelineWeight: 0); + /// /// Run the given actions to initialize the . /// @@ -251,4 +388,43 @@ public static TracerProvider Build(this TracerProviderBuilder tracerProviderBuil throw new NotSupportedException($"Build is not supported on '{tracerProviderBuilder?.GetType().FullName ?? "null"}' instances."); } + + internal static TracerProviderBuilder AddBatchExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + string? name, + Func> implementationFactory, + int pipelineWeight) + { + Guard.ThrowIfNull(implementationFactory); + + return tracerProviderBuilder.AddProcessor(sp => + { + var options = sp.GetRequiredService>().Get(name); + + var exporter = implementationFactory(sp, name) + ?? throw new InvalidOperationException("Implementation factory returned a null instance"); + + return ActivityExportProcessorFactory.CreateBatchExportProcessor( + exporter, + options.BatchExportProcessorOptions, + pipelineWeight); + }); + } + + internal static TracerProviderBuilder AddSimpleExportProcessor( + this TracerProviderBuilder tracerProviderBuilder, + string? name, + Func> implementationFactory, + int pipelineWeight) + { + Guard.ThrowIfNull(implementationFactory); + + return tracerProviderBuilder.AddProcessor(sp => + { + var exporter = implementationFactory(sp, name) + ?? throw new InvalidOperationException("Implementation factory returned a null instance"); + + return ActivityExportProcessorFactory.CreateSimpleExportProcessor(exporter, pipelineWeight); + }); + } } diff --git a/src/OpenTelemetry/Trace/Processor/ActivityExportProcessorFactory.cs b/src/OpenTelemetry/Trace/Processor/ActivityExportProcessorFactory.cs new file mode 100644 index 00000000000..195e770e88a --- /dev/null +++ b/src/OpenTelemetry/Trace/Processor/ActivityExportProcessorFactory.cs @@ -0,0 +1,46 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Diagnostics; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Trace; + +internal static class ActivityExportProcessorFactory +{ + public static BaseExportProcessor CreateBatchExportProcessor( + BaseExporter exporter, + BatchExportProcessorOptions options, + int pipelineWeight) + { + Guard.ThrowIfNull(exporter); + Guard.ThrowIfNull(options); + + return new BatchActivityExportProcessor( + exporter, + options.MaxQueueSize, + options.ScheduledDelayMilliseconds, + options.ExporterTimeoutMilliseconds, + options.MaxExportBatchSize) + { + PipelineWeight = pipelineWeight, + }; + } + + public static BaseExportProcessor CreateSimpleExportProcessor( + BaseExporter exporter, + int pipelineWeight) + { + Guard.ThrowIfNull(exporter); + + BaseExportProcessor processor = ConcurrencyModesAttribute + .GetConcurrencyModeForExporter(exporter) + .HasFlag(ConcurrencyModes.Multithreaded) + ? new SimpleMultithreadedActivityExportProcessor(exporter) + : new SimpleActivityExportProcessor(exporter); + + processor.PipelineWeight = pipelineWeight; + + return processor; + } +} diff --git a/src/OpenTelemetry/Trace/Processor/SimpleMultithreadedActivityExportProcessor.cs b/src/OpenTelemetry/Trace/Processor/SimpleMultithreadedActivityExportProcessor.cs new file mode 100644 index 00000000000..6b34219cd37 --- /dev/null +++ b/src/OpenTelemetry/Trace/Processor/SimpleMultithreadedActivityExportProcessor.cs @@ -0,0 +1,26 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Diagnostics; + +namespace OpenTelemetry.Trace; + +internal sealed class SimpleMultithreadedActivityExportProcessor : SimpleMultithreadedExportProcessor +{ + public SimpleMultithreadedActivityExportProcessor( + BaseExporter exporter) + : base(exporter) + { + } + + /// + protected override void OnExport(Activity data) + { + if (!data.Recorded) + { + return; + } + + base.OnExport(data); + } +} diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTest/IntegrationTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTest/IntegrationTests.cs index 3e40b9c6d9f..51d1b6f4532 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTest/IntegrationTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTest/IntegrationTests.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.Metrics; using System.Diagnostics.Tracing; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetry.Logs; @@ -69,11 +70,14 @@ public void TraceExportResultIsSuccess(OtlpExportProtocol protocol, string endpo var builder = Sdk.CreateTracerProviderBuilder() .AddSource(activitySourceName); - builder.AddProcessor(sp => OtlpTraceExporterHelperExtensions.BuildOtlpExporterProcessor( + builder.ConfigureBuilder((sp, builder) => OtlpTraceExporterHelperExtensions.AddOtlpTraceExporter( + name: null, serviceProvider: sp, + builder: builder, exporterOptions: exporterOptions, sdkLimitOptions: DefaultSdkLimitOptions, experimentalOptions: DefaultExperimentalOptions, + exportProcessorType: exporterOptions.ExportProcessorType, configureExporterInstance: otlpExporter => { delegatingExporter = new DelegatingExporter @@ -222,26 +226,27 @@ public void LogExportResultIsSuccess(OtlpExportProtocol protocol, string endpoin DelegatingExporter delegatingExporter; var exportResults = new List(); - var processorOptions = new LogRecordExportProcessorOptions - { - ExportProcessorType = exportProcessorType, - BatchExportProcessorOptions = new() - { - ScheduledDelayMilliseconds = ExportIntervalMilliseconds, - }, - }; using var loggerFactory = LoggerFactory.Create(builder => { builder .UseOpenTelemetry(logging => logging - .AddProcessor(sp => - OtlpLogExporterHelperExtensions.BuildOtlpLogExporter( + .ConfigureServices(services => + { + services.Configure(o => + { + o.BatchExportProcessorOptions.ScheduledDelayMilliseconds = ExportIntervalMilliseconds; + }); + }) + .ConfigureBuilder((sp, builder) => + OtlpLogExporterHelperExtensions.AddOtlpLogExporter( + name: null, sp, + builder, exporterOptions, - processorOptions, DefaultSdkLimitOptions, DefaultExperimentalOptions, + exportProcessorType, configureExporterInstance: otlpExporter => { delegatingExporter = new DelegatingExporter @@ -261,7 +266,7 @@ public void LogExportResultIsSuccess(OtlpExportProtocol protocol, string endpoin var logger = loggerFactory.CreateLogger("OtlpLogExporterTests"); logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99); - switch (processorOptions.ExportProcessorType) + switch (exportProcessorType) { case ExportProcessorType.Batch: Assert.True(handle.WaitOne(ExportIntervalMilliseconds * 2)); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs index 84d3076500a..c2192dd03c9 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using Google.Protobuf.Collections; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Transmission; using OpenTelemetry.Metrics; @@ -60,6 +61,67 @@ public void AddOtlpTraceExporterNamedOptionsSupported() Assert.Equal(1, namedExporterOptionsConfigureOptionsInvocations); } + [Theory] + [InlineData(true, null)] + [InlineData(false, null)] + [InlineData(true, "otlp")] + [InlineData(false, "otlp")] + public void AddOtlpTraceExporterBatchOptionsChangedTest(bool overrideDefaults, string? name) + { + using var sdk = OpenTelemetrySdk.Create(builder => builder + .WithTracing(tracing => tracing + .ConfigureServices(services => + { + services.Configure( + name, + o => + { + o.ExportProcessorType = ExportProcessorType.Simple; + o.BatchExportProcessorOptions.ScheduledDelayMilliseconds = 18; + }); + }) + .AddOtlpExporter( + name, + o => + { + if (overrideDefaults) + { + o.ExportProcessorType = ExportProcessorType.Batch; + o.BatchExportProcessorOptions = new() + { + ScheduledDelayMilliseconds = 10, + }; + } + }))); + + var tracerProvider = sdk.TracerProvider as TracerProviderSdk; + + Assert.NotNull(tracerProvider); + + if (overrideDefaults) + { + var batchProcessor = tracerProvider.Processor as BatchExportProcessor; + + Assert.NotNull(batchProcessor); + + Assert.Equal(10, batchProcessor.ScheduledDelayMilliseconds); + + var defaultOptions = sdk.Services.GetRequiredService>() + .Get(name); + + Assert.Equal( + ExportProcessorType.Batch, + defaultOptions.ExportProcessorType); + Assert.Equal( + 10, + defaultOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds); + } + else + { + Assert.NotNull(tracerProvider.Processor as SimpleExportProcessor); + } + } + [Fact] public void OtlpExporter_BadArgs() { diff --git a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs index 01e40b66b16..233a82bfa76 100644 --- a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs @@ -11,6 +11,7 @@ using System.Text; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using OpenTelemetry.Exporter.Zipkin.Implementation; using OpenTelemetry.Resources; using OpenTelemetry.Tests; @@ -72,7 +73,7 @@ public void Dispose() } [Fact] - public void AddAddZipkinExporterNamedOptionsSupported() + public void AddZipkinExporterNamedOptionsSupported() { int defaultExporterOptionsConfigureOptionsInvocations = 0; int namedExporterOptionsConfigureOptionsInvocations = 0; @@ -92,6 +93,72 @@ public void AddAddZipkinExporterNamedOptionsSupported() Assert.Equal(1, namedExporterOptionsConfigureOptionsInvocations); } + [Theory] + [InlineData(true, null)] + [InlineData(false, null)] + [InlineData(true, "zipkin")] + [InlineData(false, "zipkin")] + public void AddZipkinExporterBatchOptionsChangedTest(bool overrideDefaults, string name) + { + using var sdk = OpenTelemetrySdk.Create(builder => builder + .WithTracing(tracing => tracing + .ConfigureServices(services => + { + services.Configure( + name, + o => + { + o.ExportProcessorType = ExportProcessorType.Simple; + o.BatchExportProcessorOptions.ScheduledDelayMilliseconds = 18; + }); + }) + .AddZipkinExporter( + name, + o => + { + if (overrideDefaults) + { + o.ExportProcessorType = ExportProcessorType.Batch; + o.BatchExportProcessorOptions = new() + { + ScheduledDelayMilliseconds = 10, + }; + } + }))); + + var tracerProvider = sdk.TracerProvider as TracerProviderSdk; + + Assert.NotNull(tracerProvider); + + if (overrideDefaults) + { + var batchProcessor = tracerProvider.Processor as BatchExportProcessor; + + Assert.NotNull(batchProcessor); + + Assert.Equal(10, batchProcessor.ScheduledDelayMilliseconds); + + var defaultOptions = sdk.Services.GetRequiredService>() + .Get(name); + + var zipkinOptions = sdk.Services.GetRequiredService>() + .Get(name); + + Assert.False( + ReferenceEquals(defaultOptions.BatchExportProcessorOptions, zipkinOptions.BatchExportProcessorOptions)); + Assert.Equal( + defaultOptions.ExportProcessorType, + zipkinOptions.ExportProcessorType); + Assert.Equal( + defaultOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds, + zipkinOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds); + } + else + { + Assert.NotNull(tracerProvider.Processor as SimpleExportProcessor); + } + } + [Fact] public void BadArgs() {