Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add otlp log extension methods for LoggerProviderBuilder #5103

Merged
merged 42 commits into from
Dec 23, 2023
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f206708
draft
Yun-Ting Nov 30, 2023
aa42126
merge main
Yun-Ting Nov 30, 2023
b0c97f8
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 1, 2023
e11d4bb
add OTLP exporter to the LoggerProvider
Yun-Ting Dec 1, 2023
36e8560
api doc
Yun-Ting Dec 1, 2023
6723a04
extension APIs and tests
Yun-Ting Dec 1, 2023
3653fd3
more tests
Yun-Ting Dec 2, 2023
64f8df9
EXPOSE_EXPERIMENTAL_FEATURES
Yun-Ting Dec 2, 2023
b15421a
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 2, 2023
4255964
public api files
Yun-Ting Dec 2, 2023
0b853e7
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 2, 2023
3e2aff0
fix macro
Yun-Ting Dec 8, 2023
ac70c78
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 8, 2023
06893fe
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 8, 2023
7f28ee5
fixed public api file
Yun-Ting Dec 9, 2023
5fe64d3
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 9, 2023
c828fcc
api/test
Yun-Ting Dec 9, 2023
6c4d67b
flag for namedoptions test
Yun-Ting Dec 9, 2023
7276894
test flag
Yun-Ting Dec 11, 2023
7a7e962
mark apis internal when !EXPOSE_EXPERIMENTAL_FEATURES
Yun-Ting Dec 11, 2023
df0adcb
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 11, 2023
6cf59f0
test
Yun-Ting Dec 11, 2023
f08622d
Merge branch 'yunl/OtlpLoggingExtension' of https://github.com/Yun-Ti…
Yun-Ting Dec 11, 2023
35406ae
Revert "test"
Yun-Ting Dec 11, 2023
1f99014
internal visible to for project and test
Yun-Ting Dec 11, 2023
ac0494b
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 11, 2023
a350e30
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 12, 2023
fa4d229
Add ExperimentalAttribute decorations and clean up a few nits.
CodeBlanch Dec 12, 2023
04a036c
Tweaks and fixes.
CodeBlanch Dec 13, 2023
d09f1b0
changelog
Yun-Ting Dec 13, 2023
fa2857a
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 13, 2023
604ccf6
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 14, 2023
c19868d
Code review.
CodeBlanch Dec 18, 2023
e208fbc
Code review.
CodeBlanch Dec 19, 2023
c4e795f
Clean up.
CodeBlanch Dec 19, 2023
2f51df2
Code review and test improvements.
CodeBlanch Dec 19, 2023
e17f4e7
Nits
CodeBlanch Dec 19, 2023
66ea5e3
Test improvements.
CodeBlanch Dec 19, 2023
8f15ca0
Code review.
CodeBlanch Dec 23, 2023
11d7f4c
Code review.
CodeBlanch Dec 23, 2023
df362e4
Code review.
CodeBlanch Dec 23, 2023
a332701
Merge branch 'main' into yunl/OtlpLoggingExtension
Yun-Ting Dec 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#if !EXPOSE_EXPERIMENTAL_FEATURES
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Console" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.OpenTelemetryProtocol" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting" + AssemblyInfo.PublicKey)]
#endif

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder) -> OpenTelemetry.Logs.LoggerProviderBuilder!
static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, string? name, System.Action<OpenTelemetry.Exporter.OtlpExporterOptions!, OpenTelemetry.Logs.LogRecordExportProcessorOptions!>? configureExporterAndProcessor) -> OpenTelemetry.Logs.LoggerProviderBuilder!
static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, string? name, System.Action<OpenTelemetry.Exporter.OtlpExporterOptions!>? configureExporter) -> OpenTelemetry.Logs.LoggerProviderBuilder!
static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, System.Action<OpenTelemetry.Exporter.OtlpExporterOptions!, OpenTelemetry.Logs.LogRecordExportProcessorOptions!>! configureExporterAndProcessor) -> OpenTelemetry.Logs.LoggerProviderBuilder!
static OpenTelemetry.Logs.OtlpLogExporterHelperExtensions.AddOtlpExporter(this OpenTelemetry.Logs.LoggerProviderBuilder! builder, System.Action<OpenTelemetry.Exporter.OtlpExporterOptions!>! configureExporter) -> OpenTelemetry.Logs.LoggerProviderBuilder!
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

* **Experimental (pre-release builds only):** Added
`LoggerProviderBuilder.AddOtlpExporter` registration extensions.
[#5103](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5103)

## 1.7.0

Released 2023-Dec-08
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@
<!-- Note: When '$(ExposeExperimentalFeatures)' == 'false' these links are
NOT required because this project sees API + SDK internals -->
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" RequiresExposedExperimentalFeatures="true" />
<Compile Include="$(RepoRoot)\src\Shared\ResourceSemanticConventions.cs" Link="Includes\ResourceSemanticConventions.cs" RequiresExposedExperimentalFeatures="true" />
<Compile Include="$(RepoRoot)\src\Shared\DiagnosticDefinitions.cs" Link="Includes\DiagnosticDefinitions.cs" RequiresExposedExperimentalFeatures="true" />
<Compile Include="$(RepoRoot)\src\Shared\EnvironmentVariables\*.cs" Link="Includes\EnvironmentVariables\%(Filename).cs" RequiresExposedExperimentalFeatures="true" />
<Compile Include="$(RepoRoot)\src\Shared\ExceptionExtensions.cs" Link="Includes\ExceptionExtensions.cs" RequiresExposedExperimentalFeatures="true" />
<Compile Include="$(RepoRoot)\src\Shared\Options\*.cs" Link="Includes\Options\%(Filename).cs" RequiresExposedExperimentalFeatures="true" />
<Compile Include="$(RepoRoot)\src\Shared\ResourceSemanticConventions.cs" Link="Includes\ResourceSemanticConventions.cs" RequiresExposedExperimentalFeatures="true" />
<Compile Include="$(RepoRoot)\src\Shared\SemanticConventions.cs" Link="Includes\SemanticConventions.cs" RequiresExposedExperimentalFeatures="true" />
<Compile Include="$(RepoRoot)\src\Shared\SpanAttributeConstants.cs" Link="Includes\SpanAttributeConstants.cs" RequiresExposedExperimentalFeatures="true" />
<Compile Include="$(RepoRoot)\src\Shared\StatusHelper.cs" Link="Includes\StatusHelper.cs" RequiresExposedExperimentalFeatures="true" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#nullable enable

using System.Diagnostics;
#if EXPOSE_EXPERIMENTAL_FEATURES && NET8_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
#endif
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -106,29 +109,280 @@ public static OpenTelemetryLoggerOptions AddOtlpExporter(
});
}

#if EXPOSE_EXPERIMENTAL_FEATURES
/// <summary>
/// Adds an OTLP exporter to the LoggerProvider.
/// </summary>
/// <remarks><b>WARNING</b>: This is an experimental API which might change or be removed in the future. Use at your own risk.</remarks>
/// <param name="builder"><see cref="LoggerProviderBuilder"/> builder to use.</param>
/// <returns>The instance of <see cref="LoggerProviderBuilder"/> to chain the calls.</returns>
#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
#else
/// <summary>
/// Adds an OTLP exporter to the LoggerProvider.
/// </summary>
/// <param name="builder"><see cref="LoggerProviderBuilder"/> builder to use.</param>
/// <returns>The instance of <see cref="LoggerProviderBuilder"/> to chain the calls.</returns>
internal
#endif
static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder)
=> AddOtlpExporter(builder, name: null, configureExporter: null);

#if EXPOSE_EXPERIMENTAL_FEATURES
/// <summary>
/// Adds an OTLP exporter to the LoggerProvider.
/// </summary>
/// <remarks><b>WARNING</b>: This is an experimental API which might change or be removed in the future. Use at your own risk.</remarks>
/// <param name="builder"><see cref="LoggerProviderBuilder"/> builder to use.</param>
/// <param name="configureExporter">Callback action for configuring <see cref="OtlpExporterOptions"/>.</param>
/// <returns>The instance of <see cref="LoggerProviderBuilder"/> to chain the calls.</returns>
#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
#else
/// <summary>
/// Adds an OTLP exporter to the LoggerProvider.
/// </summary>
/// <param name="builder"><see cref="LoggerProviderBuilder"/> builder to use.</param>
/// <param name="configureExporter">Callback action for configuring <see cref="OtlpExporterOptions"/>.</param>
/// <returns>The instance of <see cref="LoggerProviderBuilder"/> to chain the calls.</returns>
internal
#endif
static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder, Action<OtlpExporterOptions> configureExporter)
=> AddOtlpExporter(builder, name: null, configureExporter);

#if EXPOSE_EXPERIMENTAL_FEATURES
/// <summary>
/// Adds an OTLP exporter to the LoggerProvider.
/// </summary>
/// <remarks><b>WARNING</b>: This is an experimental API which might change or be removed in the future. Use at your own risk.</remarks>
/// <param name="builder"><see cref="LoggerProviderBuilder"/> builder to use.</param>
/// <param name="configureExporterAndProcessor">Callback action for
/// configuring <see cref="OtlpExporterOptions"/> and <see
/// cref="LogRecordExportProcessorOptions"/>.</param>
/// <returns>The instance of <see cref="LoggerProviderBuilder"/> to chain the calls.</returns>
#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
#else
internal
#endif
static LoggerProviderBuilder AddOtlpExporter(this LoggerProviderBuilder builder, Action<OtlpExporterOptions, LogRecordExportProcessorOptions> configureExporterAndProcessor)
=> AddOtlpExporter(builder, name: null, configureExporterAndProcessor);

#if EXPOSE_EXPERIMENTAL_FEATURES
/// <summary>
/// Adds OpenTelemetry Protocol (OTLP) exporter to the LoggerProvider.
/// </summary>
/// <remarks><b>WARNING</b>: This is an experimental API which might change or be removed in the future. Use at your own risk.</remarks>
/// <param name="builder"><see cref="LoggerProviderBuilder"/> builder to use.</param>
/// <param name="name">Optional name which is used when retrieving options.</param>
/// <param name="configureExporter">Optional callback action for configuring <see cref="OtlpExporterOptions"/>.</param>
/// <returns>The instance of <see cref="LoggerProviderBuilder"/> to chain the calls.</returns>
#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
#else
/// <summary>
/// Adds OpenTelemetry Protocol (OTLP) exporter to the LoggerProvider.
/// </summary>
/// <param name="builder"><see cref="LoggerProviderBuilder"/> builder to use.</param>
/// <param name="name">Optional name which is used when retrieving options.</param>
/// <param name="configureExporter">Optional callback action for configuring <see cref="OtlpExporterOptions"/>.</param>
/// <returns>The instance of <see cref="LoggerProviderBuilder"/> to chain the calls.</returns>
internal
#endif
static LoggerProviderBuilder AddOtlpExporter(
this LoggerProviderBuilder builder,
string? name,
Action<OtlpExporterOptions>? configureExporter)
{
var finalOptionsName = name ?? Options.DefaultName;

builder.ConfigureServices(services =>
{
if (name != null && configureExporter != null)
{
// If we are using named options we register the
// configuration delegate into options pipeline.
services.Configure(finalOptionsName, configureExporter);
utpilla marked this conversation as resolved.
Show resolved Hide resolved
}

RegisterOptions(services);
});

return builder.AddProcessor(sp =>
{
OtlpExporterOptions exporterOptions;

if (name == null)
{
// If we are NOT using named options we create a new
// instance always. The reason for this is
// OtlpExporterOptions is shared by all signals. Without a
// name, delegates for all signals will mix together. See:
// https://github.com/open-telemetry/opentelemetry-dotnet/issues/4043
exporterOptions = sp.GetRequiredService<IOptionsFactory<OtlpExporterOptions>>().Create(finalOptionsName);

// Configuration delegate is executed inline on the fresh instance.
configureExporter?.Invoke(exporterOptions);
}
else
{
// When using named options we can properly utilize Options
// API to create or reuse an instance.
exporterOptions = sp.GetRequiredService<IOptionsMonitor<OtlpExporterOptions>>().Get(finalOptionsName);
}

// Note: Not using finalOptionsName here for SdkLimitOptions.
// There should only be one provider for a given service
// collection so SdkLimitOptions is treated as a single default
// instance.
var sdkLimitOptions = sp.GetRequiredService<IOptionsMonitor<SdkLimitOptions>>().CurrentValue;

return BuildOtlpLogExporter(
sp,
exporterOptions,
sp.GetRequiredService<IOptionsMonitor<LogRecordExportProcessorOptions>>().Get(finalOptionsName),
sdkLimitOptions,
sp.GetRequiredService<IOptionsMonitor<ExperimentalOptions>>().Get(finalOptionsName));
});
}

#if EXPOSE_EXPERIMENTAL_FEATURES
/// <summary>
/// Adds an OTLP exporter to the LoggerProvider.
/// </summary>
/// <remarks><b>WARNING</b>: This is an experimental API which might change or be removed in the future. Use at your own risk.</remarks>
/// <param name="builder"><see cref="LoggerProviderBuilder"/> builder to use.</param>
/// <param name="name">Optional name which is used when retrieving options.</param>
/// <param name="configureExporterAndProcessor">Optional callback action for
/// configuring <see cref="OtlpExporterOptions"/> and <see
/// cref="LogRecordExportProcessorOptions"/>.</param>
/// <returns>The instance of <see cref="LoggerProviderBuilder"/> to chain the calls.</returns>
#if NET8_0_OR_GREATER
[Experimental(DiagnosticDefinitions.LoggerProviderExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
#endif
public
#else
/// <summary>
/// Adds an OTLP exporter to the LoggerProvider.
/// </summary>
/// <param name="builder"><see cref="LoggerProviderBuilder"/> builder to use.</param>
/// <param name="name">Optional name which is used when retrieving options.</param>
/// <param name="configureExporterAndProcessor">Optional callback action for
/// configuring <see cref="OtlpExporterOptions"/> and <see
/// cref="LogRecordExportProcessorOptions"/>.</param>
/// <returns>The instance of <see cref="LoggerProviderBuilder"/> to chain the calls.</returns>
internal
#endif
static LoggerProviderBuilder AddOtlpExporter(
this LoggerProviderBuilder builder,
string? name,
Action<OtlpExporterOptions, LogRecordExportProcessorOptions>? configureExporterAndProcessor)
{
var finalOptionsName = name ?? Options.DefaultName;

builder.ConfigureServices(RegisterOptions);

return builder.AddProcessor(sp =>
{
OtlpExporterOptions exporterOptions;

if (name == null)
{
// If we are NOT using named options we create a new
// instance always. The reason for this is
// OtlpExporterOptions is shared by all signals. Without a
// name, delegates for all signals will mix together. See:
// https://github.com/open-telemetry/opentelemetry-dotnet/issues/4043
exporterOptions = sp.GetRequiredService<IOptionsFactory<OtlpExporterOptions>>().Create(finalOptionsName);
}
else
{
// When using named options we can properly utilize Options
// API to create or reuse an instance.
exporterOptions = sp.GetRequiredService<IOptionsMonitor<OtlpExporterOptions>>().Get(finalOptionsName);
}

var processorOptions = sp.GetRequiredService<IOptionsMonitor<LogRecordExportProcessorOptions>>().Get(finalOptionsName);

// Configuration delegate is executed inline.
configureExporterAndProcessor?.Invoke(exporterOptions, processorOptions);

// Note: Not using finalOptionsName here for SdkLimitOptions.
// There should only be one provider for a given service
// collection so SdkLimitOptions is treated as a single default
// instance.
var sdkLimitOptions = sp.GetRequiredService<IOptionsMonitor<SdkLimitOptions>>().CurrentValue;

return BuildOtlpLogExporter(
sp,
exporterOptions,
processorOptions,
sdkLimitOptions,
sp.GetRequiredService<IOptionsMonitor<ExperimentalOptions>>().Get(finalOptionsName));
});
}

internal static BaseProcessor<LogRecord> BuildOtlpLogExporter(
IServiceProvider sp,
OtlpExporterOptions exporterOptions,
LogRecordExportProcessorOptions processorOptions,
Func<BaseExporter<LogRecord>, BaseExporter<LogRecord>>? configureExporterInstance = null)
{
if (sp == null)
{
throw new ArgumentNullException(nameof(sp));
}

Debug.Assert(exporterOptions != null, "exporterOptions was null");
Debug.Assert(processorOptions != null, "processorOptions was null");
Debug.Assert(sp != null, "sp was null");

var config = sp.GetRequiredService<IConfiguration>();
var config = sp!.GetRequiredService<IConfiguration>();

var sdkLimitOptions = new SdkLimitOptions(config);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newly added AddOtlpLogExporter methods are registering OptionsFactory for SdkLimitOptions and ExperimentalOptions.

Shouldn't we be using IOptionsFactory<TOptions>.Create method to create these options?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SdkLimitOptions and ExperimentalOptions will be registered into the IOptionsFactory<T> which takes IConfiguration as one of the parameters:
https://github.com/open-telemetry/opentelemetry-dotnet/blob/e3759a1e0ea6e23b80cad33a206795fda8e240ff/src/Shared/Options/ConfigurationExtensions.cs#L137C1-L145C12
So the options can be retrieved when constructing new option instances with IConfiguration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My question is instead of using the regular ctor for SdkLimitOptions and ExperimentalOptions, shouldn't we be using either: IOptionsFactory<TOptions>.Create or IOptionsMonitor<TOptions>.Get to get these options. Shouldn't we be utilizing the OptionsFactory that we are now registering in this PR for these two options?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't as important to use Options API with SdkLimitOptions and ExperimentalOptions because they are internal but I went ahead and refactored it so it is nice and consistent now.

var experimentalOptions = new ExperimentalOptions(config);

return BuildOtlpLogExporter(sp!, exporterOptions, processorOptions, sdkLimitOptions, experimentalOptions, configureExporterInstance);
}

private static BaseProcessor<LogRecord> BuildOtlpLogExporter(
IServiceProvider sp,
OtlpExporterOptions exporterOptions,
LogRecordExportProcessorOptions processorOptions,
SdkLimitOptions sdkLimitOptions,
ExperimentalOptions experimentalOptions,
Func<BaseExporter<LogRecord>, BaseExporter<LogRecord>>? configureExporterInstance = null)
{
// Note: sp is not currently used by this method but it should be used
// at some point for IHttpClientFactory integration.
Debug.Assert(sp != null, "sp 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");

/*
* Note:
*
* We don't currently enable IHttpClientFactory for OtlpLogExporter.
*
* The DefaultHttpClientFactory requires the ILoggerFactory in its ctor:
* https://github.com/dotnet/runtime/blob/fa40ecf7d36bf4e31d7ae968807c1c529bac66d6/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpClientFactory.cs#L64
*
* This creates a circular reference: ILoggerFactory ->
* OpenTelemetryLoggerProvider -> OtlpLogExporter -> IHttpClientFactory
* -> ILoggerFactory
*
* exporterOptions.TryEnableIHttpClientFactoryIntegration(sp,
* "OtlpLogExporter");
*/

BaseExporter<LogRecord> otlpExporter = new OtlpLogExporter(
exporterOptions!,
sdkLimitOptions,
experimentalOptions);
sdkLimitOptions!,
experimentalOptions!);

if (configureExporterInstance != null)
{
Expand All @@ -152,6 +406,13 @@ internal static BaseProcessor<LogRecord> BuildOtlpLogExporter(
}
}

private static void RegisterOptions(IServiceCollection services)
{
OtlpExporterOptions.RegisterOtlpExporterOptionsFactory(services);
services.RegisterOptionsFactory(configuration => new SdkLimitOptions(configuration));
services.RegisterOptionsFactory(configuration => new ExperimentalOptions(configuration));
}

private static OtlpExporterOptions GetOtlpExporterOptions(IServiceProvider sp, string? name, string finalName)
{
// Note: If OtlpExporter has been registered for tracing and/or metrics
Expand Down
Loading