ipjohnson / Grace

Grace is a feature rich dependency injection container library
MIT License
336 stars 33 forks source link

Grace and OpenTelemetry 1.9.0 = Exception. #317

Open secovel opened 4 days ago

secovel commented 4 days ago

VERY minimal example attached.

Add Opentelemetry Tracing with OtlpExporter options. Runs fine. Add UserGrace(), get an exception. Seems like Grace much be touching some objects it shouldn't during bootstrapping.

fail: Microsoft.Extensions.Hosting.Internal.Host[11] Hosting failed to start System.NotSupportedException: Signal-specific AddOtlpExporter methods and the cross-cutting UseOtlpExporter method being invoked on the same IServiceCollection is not supported. at OpenTelemetry.Exporter.OpenTelemetryBuilderServiceProviderExtensions.EnsureNoUseOtlpExporterRegistrations(IServiceProvider serviceProvider) at OpenTelemetry.Trace.OtlpTraceExporterHelperExtensions.BuildOtlpExporterProcessor(IServiceProvider serviceProvider, OtlpExporterOptions exporterOptions, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, ExportProcessorType exportProcessorType, BatchExportProcessorOptions1 batchExportProcessorOptions, Boolean skipUseOtlpExporterRegistrationCheck, Func2 configureExporterInstance) at OpenTelemetry.Trace.OtlpTraceExporterHelperExtensions.BuildOtlpExporterProcessor(IServiceProvider serviceProvider, OtlpExporterOptions exporterOptions, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, Func2 configureExporterInstance) at OpenTelemetry.Trace.OtlpTraceExporterHelperExtensions.<>cDisplayClass2_0.b1(IServiceProvider sp) at OpenTelemetry.Trace.TracerProviderBuilderExtensions.<>cDisplayClass8_0.b0(IServiceProvider sp, TracerProviderBuilder builder) at OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.ConfigureTracerProviderBuilderCallbackWrapper.ConfigureBuilder(IServiceProvider serviceProvider, TracerProviderBuilder tracerProviderBuilder) at OpenTelemetry.Trace.TracerProviderSdk..ctor(IServiceProvider serviceProvider, Boolean ownsServiceProvider) at lambda_method101(Closure, IExportLocatorScope, IDisposalScope, IInjectionContext) at Grace.DependencyInjection.Lifestyle.SingletonLifestyle.ProvideLifestyleExpression(IInjectionScope scope, IActivationExpressionRequest request, Func2 activationExpression) at Grace.DependencyInjection.Impl.InstanceStrategies.DelegateBaseExportStrategy1.CreateExpression(IInjectionScope scope, IActivationExpressionRequest request, ICompiledLifestyle lifestyle) at Grace.DependencyInjection.Impl.InstanceStrategies.BaseInstanceExportStrategy.GetActivationExpression(IInjectionScope scope, IActivationExpressionRequest request) at Grace.DependencyInjection.Impl.InstanceStrategies.BaseInstanceExportStrategy.GetActivationStrategyDelegate(IInjectionScope scope, IActivationStrategyCompiler compiler, Type activationType) at Grace.DependencyInjection.Impl.ActivationStrategyCompiler.LocateStrategyFromCollectionContainers(IInjectionScope scope, Type locateType, ActivationStrategyFilter consider, Object key, IInjectionContext injectionContext) at Grace.DependencyInjection.Impl.ActivationStrategyCompiler.FindDelegate(IInjectionScope scope, Type locateType, ActivationStrategyFilter consider, Object key, IInjectionContext injectionContext, Boolean checkMissing) at Grace.DependencyInjection.Impl.InjectionScope.InternalLocate(IExportLocatorScope scope, IDisposalScope disposalScope, Type type, ActivationStrategyFilter consider, Object key, IInjectionContext injectionContext, Boolean allowNull, Boolean isDynamic) at Grace.DependencyInjection.Impl.InjectionScope.Grace.DependencyInjection.IInjectionScope.LocateFromChildScope(IExportLocatorScope childScope, IDisposalScope disposalScope, Type type, Object extraData, ActivationStrategyFilter consider, Object key, Boolean allowNull, Boolean isDynamic) at Grace.DependencyInjection.Impl.ActivationStrategyDelegateCache.FallbackExecution(ImmutableHashTree2 currentNode, Type type, IExportLocatorScope scope, Boolean allowNull, IInjectionContext context) at Grace.DependencyInjection.Impl.ActivationStrategyDelegateCache.ExecuteActivationStrategyDelegateAllowNull(Type type, IExportLocatorScope scope) at Grace.DependencyInjection.Impl.BaseExportLocatorScope.LocateOrDefault(Type type, Object defaultValue) at Grace.DependencyInjection.Extensions.GraceRegistration.GraceServiceProvider.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider) at OpenTelemetry.Extensions.Hosting.Implementation.TelemetryHostedService.Initialize(IServiceProvider serviceProvider) at OpenTelemetry.Extensions.Hosting.Implementation.TelemetryHostedService.StartAsync(CancellationToken cancellationToken) at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>b__15_1(IHostedService service, CancellationToken token) at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List1 exceptions, Func3 operation) Unhandled exception. System.NotSupportedException: Signal-specific AddOtlpExporter methods and the cross-cutting UseOtlpExporter method being invoked on the same IServiceCollection is not supported. at OpenTelemetry.Exporter.OpenTelemetryBuilderServiceProviderExtensions.EnsureNoUseOtlpExporterRegistrations(IServiceProvider serviceProvider) at OpenTelemetry.Trace.OtlpTraceExporterHelperExtensions.BuildOtlpExporterProcessor(IServiceProvider serviceProvider, OtlpExporterOptions exporterOptions, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, ExportProcessorType exportProcessorType, BatchExportProcessorOptions1 batchExportProcessorOptions, Boolean skipUseOtlpExporterRegistrationCheck, Func2 configureExporterInstance) at OpenTelemetry.Trace.OtlpTraceExporterHelperExtensions.BuildOtlpExporterProcessor(IServiceProvider serviceProvider, OtlpExporterOptions exporterOptions, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, Func2 configureExporterInstance) at OpenTelemetry.Trace.OtlpTraceExporterHelperExtensions.<>c__DisplayClass2_0.<AddOtlpExporter>b__1(IServiceProvider sp) at OpenTelemetry.Trace.TracerProviderBuilderExtensions.<>c__DisplayClass8_0.<AddProcessor>b__0(IServiceProvider sp, TracerProviderBuilder builder) at OpenTelemetry.Trace.OpenTelemetryDependencyInjectionTracingServiceCollectionExtensions.ConfigureTracerProviderBuilderCallbackWrapper.ConfigureBuilder(IServiceProvider serviceProvider, TracerProviderBuilder tracerProviderBuilder) at OpenTelemetry.Trace.TracerProviderSdk..ctor(IServiceProvider serviceProvider, Boolean ownsServiceProvider) at lambda_method101(Closure, IExportLocatorScope, IDisposalScope, IInjectionContext) at Grace.DependencyInjection.Lifestyle.SingletonLifestyle.ProvideLifestyleExpression(IInjectionScope scope, IActivationExpressionRequest request, Func2 activationExpression) at Grace.DependencyInjection.Impl.InstanceStrategies.DelegateBaseExportStrategy1.CreateExpression(IInjectionScope scope, IActivationExpressionRequest request, ICompiledLifestyle lifestyle) at Grace.DependencyInjection.Impl.InstanceStrategies.BaseInstanceExportStrategy.GetActivationExpression(IInjectionScope scope, IActivationExpressionRequest request) at Grace.DependencyInjection.Impl.InstanceStrategies.BaseInstanceExportStrategy.GetActivationStrategyDelegate(IInjectionScope scope, IActivationStrategyCompiler compiler, Type activationType) at Grace.DependencyInjection.Impl.ActivationStrategyCompiler.LocateStrategyFromCollectionContainers(IInjectionScope scope, Type locateType, ActivationStrategyFilter consider, Object key, IInjectionContext injectionContext) at Grace.DependencyInjection.Impl.ActivationStrategyCompiler.FindDelegate(IInjectionScope scope, Type locateType, ActivationStrategyFilter consider, Object key, IInjectionContext injectionContext, Boolean checkMissing) at Grace.DependencyInjection.Impl.InjectionScope.InternalLocate(IExportLocatorScope scope, IDisposalScope disposalScope, Type type, ActivationStrategyFilter consider, Object key, IInjectionContext injectionContext, Boolean allowNull, Boolean isDynamic) at Grace.DependencyInjection.Impl.InjectionScope.Grace.DependencyInjection.IInjectionScope.LocateFromChildScope(IExportLocatorScope childScope, IDisposalScope disposalScope, Type type, Object extraData, ActivationStrategyFilter consider, Object key, Boolean allowNull, Boolean isDynamic) at Grace.DependencyInjection.Impl.ActivationStrategyDelegateCache.FallbackExecution(ImmutableHashTree2 currentNode, Type type, IExportLocatorScope scope, Boolean allowNull, IInjectionContext context) at Grace.DependencyInjection.Impl.ActivationStrategyDelegateCache.ExecuteActivationStrategyDelegateAllowNull(Type type, IExportLocatorScope scope) at Grace.DependencyInjection.Impl.BaseExportLocatorScope.LocateOrDefault(Type type, Object defaultValue) at Grace.DependencyInjection.Extensions.GraceRegistration.GraceServiceProvider.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider) at OpenTelemetry.Extensions.Hosting.Implementation.TelemetryHostedService.Initialize(IServiceProvider serviceProvider) at OpenTelemetry.Extensions.Hosting.Implementation.TelemetryHostedService.StartAsync(CancellationToken cancellationToken) at Microsoft.Extensions.Hosting.Internal.Host.b__15_1(IHostedService service, CancellationToken token) at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List1 exceptions, Func3 operation) at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host) at Program.<Main>$(String[] args) in /Users/scovel/RiderProjects/WebApplication8/WebApplication8/Program.cs:line 63

secovel commented 4 days ago

Can't seem to attach a file, so here's Program.cs and the csproj file

`using System.Diagnostics; using Grace.AspNetCore.Hosting; using OpenTelemetry.Exporter; using OpenTelemetry.Resources; using OpenTelemetry.Trace;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container. builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen();

//Comment out and the service starts builder.Host.UseGrace();

region Tracing

var resourceBuilder = ResourceBuilder.CreateDefault() .AddService(serviceName: "OpenTelementryTest.Service", serviceVersion: "1.0.0");

ActivitySource myActivitySource = new ActivitySource("OpenTelementryTest.Service", "1.0.0");

builder.Services.AddSingleton(myActivitySource);

builder.Services.AddOpenTelemetry().WithTracing(tracerProviderBuilder => { tracerProviderBuilder.SetSampler(new AlwaysOnSampler()); tracerProviderBuilder.AddSource("OpenTelementryTest.Service") .AddSource(myActivitySource.Name) .SetResourceBuilder(resourceBuilder);

tracerProviderBuilder.AddOtlpExporter(options =>
{
    options.Endpoint = new Uri("https://live.dynatrace.com/api/v2/otlp/v1/traces");
    options.Headers = "Authorization=Api-Token XXXXXXXXXXX";
    options.Protocol = OtlpExportProtocol.HttpProtobuf;
});

});

endregion

var app = builder.Build();

var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };

app.MapGet("/weatherforecast", () => { var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast ( DateOnly.FromDateTime(DateTime.Now.AddDays(index)), Random.Shared.Next(-20, 55), summaries[Random.Shared.Next(summaries.Length)] )) .ToArray(); return forecast; }) .WithName("GetWeatherForecast");

app.Run();

record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) { public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); }`

`

<PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

<ItemGroup>
    <PackageReference Include="Grace.AspNetCore.Hosting" Version="7.1.0" />
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6" />
    <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
    <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>

`

secovel commented 2 days ago

to narrow it down further. It all worked with OpenTelemetry 1.7.0. I think after that they turned on some "error checking" code that seems to be triggering the exception when Grace pokes some object.

Seems to be this code block that triggers the bad behavior:

tracerProviderBuilder.AddOtlpExporter(options => { options.Endpoint = new Uri("https://live.dynatrace.com/api/v2/otlp/v1/traces"); options.Headers = "Authorization=Api-Token XXXXXXXXXXX"; options.Protocol = OtlpExportProtocol.HttpProtobuf; });

I need it to send Tracing to a specific Otel ingestion point for Dynatrace. In the full code I have blocks for metrics and logging as well, each has it's own endpoint.