[Hosting] Throw startup exceptions (#4006)
* Allow the hosting startup to throw for valid issues. * CHANGELOG stub. * CHANGELOG patch. * Warning cleanup. * Code review.
This commit is contained in:
parent
733a8689ef
commit
a44a58bb7e
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
* If the OpenTelemetry SDK cannot start it will now throw exceptions and prevent
|
||||
the host from starting.
|
||||
([#4006](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4006))
|
||||
|
||||
## 1.4.0-rc.1
|
||||
|
||||
Released 2022-Dec-12
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
// </copyright>
|
||||
|
||||
using System.Diagnostics.Tracing;
|
||||
using OpenTelemetry.Internal;
|
||||
|
||||
namespace OpenTelemetry.Extensions.Hosting.Implementation
|
||||
{
|
||||
|
|
@ -27,34 +26,16 @@ namespace OpenTelemetry.Extensions.Hosting.Implementation
|
|||
{
|
||||
public static HostingExtensionsEventSource Log = new();
|
||||
|
||||
[NonEvent]
|
||||
public void FailedInitialize(Exception ex)
|
||||
[Event(1, Message = "OpenTelemetry TracerProvider was not found in application services. Tracing will remain disabled.", Level = EventLevel.Warning)]
|
||||
public void TracerProviderNotRegistered()
|
||||
{
|
||||
if (this.IsEnabled(EventLevel.Error, EventKeywords.All))
|
||||
{
|
||||
this.FailedInitialize(ex.ToInvariantString());
|
||||
}
|
||||
this.WriteEvent(1);
|
||||
}
|
||||
|
||||
[NonEvent]
|
||||
public void FailedOpenTelemetrySDK(Exception ex)
|
||||
[Event(2, Message = "OpenTelemetry MeterProvider was not found in application services. Metrics will remain disabled.", Level = EventLevel.Warning)]
|
||||
public void MeterProviderNotRegistered()
|
||||
{
|
||||
if (this.IsEnabled(EventLevel.Error, EventKeywords.All))
|
||||
{
|
||||
this.FailedOpenTelemetrySDK(ex.ToInvariantString());
|
||||
}
|
||||
}
|
||||
|
||||
[Event(1, Message = "An exception occurred while initializing OpenTelemetry Tracing. OpenTelemetry tracing will remain disabled. Exception: '{0}'.", Level = EventLevel.Error)]
|
||||
public void FailedInitialize(string exception)
|
||||
{
|
||||
this.WriteEvent(1, exception);
|
||||
}
|
||||
|
||||
[Event(2, Message = "An exception occurred while retrieving OpenTelemetry Tracer. OpenTelemetry tracing will remain disabled. Exception: '{0}'.", Level = EventLevel.Error)]
|
||||
public void FailedOpenTelemetrySDK(string exception)
|
||||
{
|
||||
this.WriteEvent(2, exception);
|
||||
this.WriteEvent(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,16 +33,9 @@ internal sealed class TelemetryHostedService : IHostedService
|
|||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
// The sole purpose of this HostedService is to ensure all
|
||||
// instrumentations, exporters, etc., are created and started.
|
||||
Initialize(this.serviceProvider);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HostingExtensionsEventSource.Log.FailedOpenTelemetrySDK(ex);
|
||||
}
|
||||
// The sole purpose of this HostedService is to ensure all
|
||||
// instrumentations, exporters, etc., are created and started.
|
||||
Initialize(this.serviceProvider);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
|
@ -57,11 +50,15 @@ internal sealed class TelemetryHostedService : IHostedService
|
|||
Debug.Assert(serviceProvider != null, "serviceProvider was null");
|
||||
|
||||
var meterProvider = serviceProvider.GetService<MeterProvider>();
|
||||
var tracerProvider = serviceProvider.GetService<TracerProvider>();
|
||||
|
||||
if (meterProvider == null && tracerProvider == null)
|
||||
if (meterProvider == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not resolve either MeterProvider or TracerProvider through application ServiceProvider, OpenTelemetry SDK has not been initialized.");
|
||||
HostingExtensionsEventSource.Log.MeterProviderNotRegistered();
|
||||
}
|
||||
|
||||
var tracerProvider = serviceProvider.GetService<TracerProvider>();
|
||||
if (tracerProvider == null)
|
||||
{
|
||||
HostingExtensionsEventSource.Log.TracerProviderNotRegistered();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
// <copyright file="TelemetryHostedServiceTests.cs" company="OpenTelemetry Authors">
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// </copyright>
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using OpenTelemetry.Trace;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Extensions.Hosting.Tests;
|
||||
|
||||
public class TelemetryHostedServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task StartWithoutProvidersDoesNotThrow()
|
||||
{
|
||||
var builder = new HostBuilder().ConfigureServices(services =>
|
||||
{
|
||||
services.AddOpenTelemetry()
|
||||
.StartWithHost();
|
||||
});
|
||||
|
||||
var host = builder.Build();
|
||||
|
||||
await host.StartAsync().ConfigureAwait(false);
|
||||
|
||||
await host.StopAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StartWithExceptionsThrows()
|
||||
{
|
||||
bool expectedInnerExceptionThrown = false;
|
||||
|
||||
var builder = new HostBuilder().ConfigureServices(services =>
|
||||
{
|
||||
services.AddOpenTelemetry()
|
||||
.WithTracing(builder =>
|
||||
{
|
||||
builder.ConfigureBuilder((sp, sdkBuilder) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// Note: This throws because services cannot be
|
||||
// registered after IServiceProvider has been
|
||||
// created.
|
||||
sdkBuilder.SetSampler<MySampler>();
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
expectedInnerExceptionThrown = true;
|
||||
throw;
|
||||
}
|
||||
});
|
||||
})
|
||||
.StartWithHost();
|
||||
});
|
||||
|
||||
var host = builder.Build();
|
||||
|
||||
await Assert.ThrowsAsync<NotSupportedException>(() => host.StartAsync()).ConfigureAwait(false);
|
||||
|
||||
await host.StopAsync().ConfigureAwait(false);
|
||||
|
||||
Assert.True(expectedInnerExceptionThrown);
|
||||
}
|
||||
|
||||
private sealed class MySampler : Sampler
|
||||
{
|
||||
public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
|
||||
=> new SamplingResult(SamplingDecision.RecordAndSample);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue