diff --git a/build/Common.props b/build/Common.props
index d47bf985f5e..a1d08f1e37d 100644
--- a/build/Common.props
+++ b/build/Common.props
@@ -37,7 +37,8 @@
[17.4.1]
[3.1.0,)
$(MicrosoftExtensionsDependencyInjectionPkgVer)
- [2.1.0,)
+ [2.1.0,)
+ $(MicrosoftExtensionsHostingPkgVer)
[3.1.0,)
$(MicrosoftExtensionsLoggingPkgVer)
[3.1.0,)
diff --git a/docs/trace/getting-started-aspnetcore/Program.cs b/docs/trace/getting-started-aspnetcore/Program.cs
index 2feba0bd229..a2914077175 100644
--- a/docs/trace/getting-started-aspnetcore/Program.cs
+++ b/docs/trace/getting-started-aspnetcore/Program.cs
@@ -27,8 +27,7 @@
.AddService(serviceName: "OTel.NET Getting Started"))
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
- .AddConsoleExporter())
- .StartWithHost();
+ .AddConsoleExporter());
var app = appBuilder.Build();
diff --git a/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj b/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj
index 1956f427004..321fbcd608b 100644
--- a/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj
+++ b/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj
@@ -8,7 +8,6 @@
-
diff --git a/examples/AspNetCore/Examples.AspNetCore.csproj b/examples/AspNetCore/Examples.AspNetCore.csproj
index b8b09bcd9d4..7e29680340f 100644
--- a/examples/AspNetCore/Examples.AspNetCore.csproj
+++ b/examples/AspNetCore/Examples.AspNetCore.csproj
@@ -10,7 +10,6 @@
-
diff --git a/examples/AspNetCore/Program.cs b/examples/AspNetCore/Program.cs
index 53245406d57..80527159685 100644
--- a/examples/AspNetCore/Program.cs
+++ b/examples/AspNetCore/Program.cs
@@ -44,8 +44,7 @@
// for manual instrumentation
appBuilder.Services.AddSingleton();
-// Configure OpenTelemetry tracing & metrics with auto-start using the
-// StartWithHost extension from OpenTelemetry.Extensions.Hosting.
+// Configure OpenTelemetry tracing & metrics.
appBuilder.Services.AddOpenTelemetry()
.ConfigureResource(configureResource)
.WithTracing(builder =>
@@ -127,8 +126,7 @@
builder.AddConsoleExporter();
break;
}
- })
- .StartWithHost();
+ });
// Clear default logging providers used by WebApplication host.
appBuilder.Logging.ClearProviders();
diff --git a/examples/GrpcService/Examples.GrpcService.csproj b/examples/GrpcService/Examples.GrpcService.csproj
index 2a9028e8650..7123737717a 100644
--- a/examples/GrpcService/Examples.GrpcService.csproj
+++ b/examples/GrpcService/Examples.GrpcService.csproj
@@ -16,7 +16,6 @@
-
diff --git a/examples/GrpcService/Startup.cs b/examples/GrpcService/Startup.cs
index 2c875eae04b..32d595ab63d 100644
--- a/examples/GrpcService/Startup.cs
+++ b/examples/GrpcService/Startup.cs
@@ -61,8 +61,7 @@ public void ConfigureServices(IServiceCollection services)
builder.AddConsoleExporter();
break;
}
- })
- .StartWithHost();
+ });
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
diff --git a/examples/MicroserviceExample/WebApi/Startup.cs b/examples/MicroserviceExample/WebApi/Startup.cs
index 90e66783302..d3966c26aa2 100644
--- a/examples/MicroserviceExample/WebApi/Startup.cs
+++ b/examples/MicroserviceExample/WebApi/Startup.cs
@@ -43,8 +43,7 @@ public void ConfigureServices(IServiceCollection services)
{
var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost";
b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans");
- }))
- .StartWithHost();
+ }));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
diff --git a/examples/MicroserviceExample/WebApi/WebApi.csproj b/examples/MicroserviceExample/WebApi/WebApi.csproj
index 876450b7176..5e1695e9c86 100644
--- a/examples/MicroserviceExample/WebApi/WebApi.csproj
+++ b/examples/MicroserviceExample/WebApi/WebApi.csproj
@@ -10,7 +10,6 @@
-
diff --git a/examples/MicroserviceExample/WorkerService/Program.cs b/examples/MicroserviceExample/WorkerService/Program.cs
index 665265cedd4..75ad1223e16 100644
--- a/examples/MicroserviceExample/WorkerService/Program.cs
+++ b/examples/MicroserviceExample/WorkerService/Program.cs
@@ -42,8 +42,7 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
{
var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost";
b.Endpoint = new Uri($"http://{zipkinHostName}:9411/api/v2/spans");
- }))
- .StartWithHost();
+ }));
});
}
}
diff --git a/examples/MicroserviceExample/WorkerService/WorkerService.csproj b/examples/MicroserviceExample/WorkerService/WorkerService.csproj
index 926e55dd6fd..29d72978cd5 100644
--- a/examples/MicroserviceExample/WorkerService/WorkerService.csproj
+++ b/examples/MicroserviceExample/WorkerService/WorkerService.csproj
@@ -11,7 +11,6 @@
-
diff --git a/src/OpenTelemetry.Exporter.Jaeger/README.md b/src/OpenTelemetry.Exporter.Jaeger/README.md
index 411e3d40283..643d9874819 100644
--- a/src/OpenTelemetry.Exporter.Jaeger/README.md
+++ b/src/OpenTelemetry.Exporter.Jaeger/README.md
@@ -98,8 +98,7 @@ services.AddOpenTelemetry()
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
return client;
};
- }))
- .StartWithHost();
+ }));
```
For users using
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md
index 369b6e1574e..177f9639443 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md
@@ -135,8 +135,7 @@ services.AddOpenTelemetry()
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
return client;
};
- }))
- .StartWithHost();
+ }));
```
For users using
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md
index 6bcd236b5bb..e6676934961 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md
@@ -28,8 +28,7 @@ dotnet add package --prerelease OpenTelemetry.Exporter.Prometheus.AspNetCore
```csharp
services.AddOpenTelemetry()
.WithMetrics(builder => builder
- .AddPrometheusExporter())
- .StartWithHost();
+ .AddPrometheusExporter());
```
* Or configure directly:
diff --git a/src/OpenTelemetry.Exporter.Zipkin/README.md b/src/OpenTelemetry.Exporter.Zipkin/README.md
index 20d794c051d..aa277b7fdc2 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/README.md
+++ b/src/OpenTelemetry.Exporter.Zipkin/README.md
@@ -87,8 +87,7 @@ services.AddOpenTelemetry()
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
return client;
- }))
- .StartWithHost();
+ }));
```
For users using
diff --git a/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
index dbee0f5b37d..63141a61d05 100644
--- a/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
@@ -1,6 +1,5 @@
Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions
OpenTelemetry.Metrics.MeterProviderBuilderExtensions
-OpenTelemetry.OpenTelemetryBuilderHostingExtensions
OpenTelemetry.Trace.TracerProviderBuilderExtensions
static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
@@ -8,6 +7,5 @@ static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.
static Microsoft.Extensions.DependencyInjection.OpenTelemetryServicesExtensions.AddOpenTelemetryTracing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.Configure(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.GetServices(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
-static OpenTelemetry.OpenTelemetryBuilderHostingExtensions.StartWithHost(this OpenTelemetry.OpenTelemetryBuilder builder) -> OpenTelemetry.OpenTelemetryBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.Configure(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.GetServices(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder) -> Microsoft.Extensions.DependencyInjection.IServiceCollection
diff --git a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
index 8e7983ec511..b31b6c4ccb3 100644
--- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
+++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
@@ -2,6 +2,12 @@
## Unreleased
+* Removed the `OpenTelemetryBuilder.StartWithHost` extension and moved the
+ functionality into the SDK `AddOpenTelemetry` extension. With this change
+ `OpenTelemetry.Extensions.Hosting` is no longer needed and will be marked as
+ deprecated.
+ ([#4151](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4151))
+
## 1.4.0-rc.3
Released 2023-Feb-01
diff --git a/src/OpenTelemetry.Extensions.Hosting/Implementation/HostingExtensionsEventSource.cs b/src/OpenTelemetry.Extensions.Hosting/Implementation/HostingExtensionsEventSource.cs
deleted file mode 100644
index f6f86038cfe..00000000000
--- a/src/OpenTelemetry.Extensions.Hosting/Implementation/HostingExtensionsEventSource.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using System.Diagnostics.Tracing;
-
-namespace OpenTelemetry.Extensions.Hosting.Implementation
-{
- ///
- /// EventSource events emitted from the project.
- ///
- [EventSource(Name = "OpenTelemetry-Extensions-Hosting")]
- internal sealed class HostingExtensionsEventSource : EventSource
- {
- public static HostingExtensionsEventSource Log = new();
-
- [Event(1, Message = "OpenTelemetry TracerProvider was not found in application services. Tracing will remain disabled.", Level = EventLevel.Warning)]
- public void TracerProviderNotRegistered()
- {
- this.WriteEvent(1);
- }
-
- [Event(2, Message = "OpenTelemetry MeterProvider was not found in application services. Metrics will remain disabled.", Level = EventLevel.Warning)]
- public void MeterProviderNotRegistered()
- {
- this.WriteEvent(2);
- }
- }
-}
diff --git a/src/OpenTelemetry.Extensions.Hosting/Implementation/TelemetryHostedService.cs b/src/OpenTelemetry.Extensions.Hosting/Implementation/TelemetryHostedService.cs
deleted file mode 100644
index 78e50395b59..00000000000
--- a/src/OpenTelemetry.Extensions.Hosting/Implementation/TelemetryHostedService.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using System.Diagnostics;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using OpenTelemetry.Metrics;
-using OpenTelemetry.Trace;
-
-namespace OpenTelemetry.Extensions.Hosting.Implementation;
-
-internal sealed class TelemetryHostedService : IHostedService
-{
- private readonly IServiceProvider serviceProvider;
-
- public TelemetryHostedService(IServiceProvider serviceProvider)
- {
- this.serviceProvider = serviceProvider;
- }
-
- public Task StartAsync(CancellationToken cancellationToken)
- {
- // The sole purpose of this HostedService is to ensure all
- // instrumentations, exporters, etc., are created and started.
- Initialize(this.serviceProvider);
-
- return Task.CompletedTask;
- }
-
- public Task StopAsync(CancellationToken cancellationToken)
- {
- return Task.CompletedTask;
- }
-
- internal static void Initialize(IServiceProvider serviceProvider)
- {
- Debug.Assert(serviceProvider != null, "serviceProvider was null");
-
- var meterProvider = serviceProvider.GetService();
- if (meterProvider == null)
- {
- HostingExtensionsEventSource.Log.MeterProviderNotRegistered();
- }
-
- var tracerProvider = serviceProvider.GetService();
- if (tracerProvider == null)
- {
- HostingExtensionsEventSource.Log.TracerProviderNotRegistered();
- }
- }
-}
diff --git a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilderHostingExtensions.cs b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilderHostingExtensions.cs
deleted file mode 100644
index 646ca614f44..00000000000
--- a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilderHostingExtensions.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using Microsoft.Extensions.Hosting;
-using OpenTelemetry.Extensions.Hosting.Implementation;
-using OpenTelemetry.Internal;
-
-namespace OpenTelemetry;
-
-///
-/// Contains hosting extension methods for the class.
-///
-public static class OpenTelemetryBuilderHostingExtensions
-{
- ///
- /// Registers an to automatically start all
- /// configured OpenTelemetry services in the supplied .
- ///
- ///
- /// Note: This is safe to be called multiple times. Only a single will be created for a given . This should generally be called by hosting
- /// application code and NOT library authors.
- ///
- /// .
- /// The supplied for chaining
- /// calls.
- public static OpenTelemetryBuilder StartWithHost(this OpenTelemetryBuilder builder)
- {
- Guard.ThrowIfNull(builder);
-
- builder.Services.TryAddEnumerable(
- ServiceDescriptor.Singleton());
-
- return builder;
- }
-}
diff --git a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs
index 64e837fbf16..ce238c273f7 100644
--- a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs
+++ b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryServicesExtensions.cs
@@ -51,7 +51,7 @@ public static class OpenTelemetryServicesExtensions
/// .
/// Supplied for chaining
/// calls.
- [Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
+ [Obsolete("Use the AddOpenTelemetry().WithTracing(configure) pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services)
=> AddOpenTelemetryTracing(services, b => { });
@@ -68,10 +68,10 @@ public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection
/// cref="TracerProviderBuilder"/>.
/// Supplied for chaining
/// calls.
- [Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
+ [Obsolete("Use the AddOpenTelemetry().WithTracing(configure) pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Action configure)
{
- services.AddOpenTelemetry().WithTracing(configure).StartWithHost();
+ services.AddOpenTelemetry().WithTracing(configure);
return services;
}
@@ -100,7 +100,7 @@ public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection
/// .
/// Supplied for chaining
/// calls.
- [Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
+ [Obsolete("Use the AddOpenTelemetry().WithMetrics(configure) pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services)
=> AddOpenTelemetryMetrics(services, b => { });
@@ -117,10 +117,10 @@ public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection
/// cref="TracerProviderBuilder"/>.
/// Supplied for chaining
/// calls.
- [Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
+ [Obsolete("Use the AddOpenTelemetry().WithMetrics(configure) pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Action configure)
{
- services.AddOpenTelemetry().WithMetrics(configure).StartWithHost();
+ services.AddOpenTelemetry().WithMetrics(configure);
return services;
}
diff --git a/src/OpenTelemetry.Extensions.Hosting/README.md b/src/OpenTelemetry.Extensions.Hosting/README.md
index a1703580f07..59014925824 100644
--- a/src/OpenTelemetry.Extensions.Hosting/README.md
+++ b/src/OpenTelemetry.Extensions.Hosting/README.md
@@ -21,17 +21,6 @@ and metrics (`MeterProvider`) in [ASP.NET
## Extension method reference
-### Current OpenTelemetry SDK v1.4.0 and newer extensions
-
-Targeting `OpenTelemetry.OpenTelemetryBuilder`:
-
-* `StartWithHost`: Registers an
- [IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice)
- to automatically start tracing and/or metric services in the supplied
- [IServiceCollection](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.iservicecollection).
-
-### Obsolete OpenTelemetry SDK pre-1.4.0 extensions
-
> **Note**
> The below extension methods should be called by application host code
only. Library authors see: [Registration extension method guidance for library
@@ -72,10 +61,9 @@ using OpenTelemetry.Trace;
var appBuilder = WebApplication.CreateBuilder(args);
-appBuilder.Services.AddOpenTelemetry()
- .WithTracing(builder => builder.AddConsoleExporter())
- .WithMetrics(builder => builder.AddConsoleExporter())
- .StartWithHost();
+appBuilder.Services.AddOpenTelemetryTracing(builder => builder.AddConsoleExporter());
+
+appBuilder.Services.AddOpenTelemetryMetrics(builder => builder.AddConsoleExporter());
var app = appBuilder.Build();
diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/README.md b/src/OpenTelemetry.Instrumentation.AspNetCore/README.md
index 59e489b8676..fd535b1682c 100644
--- a/src/OpenTelemetry.Instrumentation.AspNetCore/README.md
+++ b/src/OpenTelemetry.Instrumentation.AspNetCore/README.md
@@ -58,8 +58,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
- .AddJaegerExporter())
- .StartWithHost();
+ .AddJaegerExporter());
}
```
@@ -88,8 +87,7 @@ services.Configure(options =>
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
- .AddJaegerExporter())
- .StartWithHost();
+ .AddJaegerExporter());
```
### Filter
@@ -112,8 +110,7 @@ services.AddOpenTelemetry()
// only collect telemetry about HTTP GET requests
return httpContext.Request.Method.Equals("GET");
})
- .AddJaegerExporter())
- .StartWithHost();
+ .AddJaegerExporter());
```
It is important to note that this `Filter` option is specific to this
@@ -150,8 +147,7 @@ services.AddOpenTelemetry()
{
activity.SetTag("exceptionType", exception.GetType().ToString());
};
- }))
- .StartWithHost();
+ }));
```
[Processor](../../docs/trace/extending-the-sdk/README.md#processor),
diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md b/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md
index 62bb0853aea..bfb6dfbb701 100644
--- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md
+++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md
@@ -120,8 +120,7 @@ services.AddOpenTelemetry()
{
activity.SetTag("responseVersion", httpResponseMessage.Version);
};
- })
- .StartWithHost();
+ });
```
[Processor](../../docs/trace/extending-the-sdk/README.md#processor),
diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md
index 9940288268f..2b03fe7dcaa 100644
--- a/src/OpenTelemetry/CHANGELOG.md
+++ b/src/OpenTelemetry/CHANGELOG.md
@@ -5,6 +5,10 @@
* Removed the dependency on System.Reflection.Emit.Lightweight
([#4140](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4140))
+* The `AddOpenTelemetry` extension will now register an `IHostedService` if
+ `Microsoft.Extensions.Hosting.Abstractions` is detected.
+ ([#4151](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4151))
+
## 1.4.0-rc.3
Released 2023-Feb-01
diff --git a/src/OpenTelemetry/Internal/EnvironmentVariables/EnvironmentVariablesExtensions.cs b/src/OpenTelemetry/Internal/EnvironmentVariables/EnvironmentVariablesExtensions.cs
index 5b97e90ce77..02928d154d5 100644
--- a/src/OpenTelemetry/Internal/EnvironmentVariables/EnvironmentVariablesExtensions.cs
+++ b/src/OpenTelemetry/Internal/EnvironmentVariables/EnvironmentVariablesExtensions.cs
@@ -4,49 +4,24 @@
#nullable enable
-using System;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.EnvironmentVariables;
-namespace Microsoft.Extensions.Configuration
+namespace OpenTelemetry.Internal;
+
+///
+/// Extension methods for registering with .
+///
+internal static class EnvironmentVariablesExtensions
{
///
- /// Extension methods for registering with .
+ /// Adds an that reads configuration values from environment variables.
///
- internal static class EnvironmentVariablesExtensions
+ /// The to add to.
+ /// The .
+ public static IConfigurationBuilder AddEnvironmentVariables(this IConfigurationBuilder configurationBuilder)
{
- ///
- /// Adds an that reads configuration values from environment variables.
- ///
- /// The to add to.
- /// The .
- public static IConfigurationBuilder AddEnvironmentVariables(this IConfigurationBuilder configurationBuilder)
- {
- configurationBuilder.Add(new EnvironmentVariablesConfigurationSource());
- return configurationBuilder;
- }
-
- ///
- /// Adds an that reads configuration values from environment variables
- /// with a specified prefix.
- ///
- /// The to add to.
- /// The prefix that environment variable names must start with. The prefix will be removed from the environment variable names.
- /// The .
- public static IConfigurationBuilder AddEnvironmentVariables(
- this IConfigurationBuilder configurationBuilder,
- string? prefix)
- {
- configurationBuilder.Add(new EnvironmentVariablesConfigurationSource { Prefix = prefix });
- return configurationBuilder;
- }
-
- ///
- /// Adds an that reads configuration values from environment variables.
- ///
- /// The to add to.
- /// Configures the source.
- /// The .
- public static IConfigurationBuilder AddEnvironmentVariables(this IConfigurationBuilder builder, Action? configureSource)
- => builder.Add(configureSource);
+ configurationBuilder.Add(new EnvironmentVariablesConfigurationSource());
+ return configurationBuilder;
}
}
diff --git a/src/OpenTelemetry/Internal/HostingHelper.cs b/src/OpenTelemetry/Internal/HostingHelper.cs
new file mode 100644
index 00000000000..58708f0aad6
--- /dev/null
+++ b/src/OpenTelemetry/Internal/HostingHelper.cs
@@ -0,0 +1,253 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#nullable enable
+
+using System.Diagnostics;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.CompilerServices;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Trace;
+
+namespace OpenTelemetry.Internal;
+
+internal static class HostingHelper
+{
+ private static readonly object LockObject = new();
+ private static bool initialized;
+ private static Type? hostedServiceImplementation;
+
+ public static void AddOpenTelemetryHostedServiceIntoServiceCollection(IServiceCollection services)
+ {
+ if (TryAddOpenTelemetryHostedServiceIntoServiceCollection(services, out var reason))
+ {
+ OpenTelemetrySdkEventSource.Log.HostedServiceRegistered();
+ }
+ else
+ {
+ OpenTelemetrySdkEventSource.Log.HostedServiceRegistrationSkipped(reason);
+ }
+ }
+
+ private static bool TryAddOpenTelemetryHostedServiceIntoServiceCollection(IServiceCollection services, out string? reason)
+ {
+#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
+ bool isDynamicCodeSupported = RuntimeFeature.IsDynamicCodeSupported;
+#else
+ // Note: This is for .NET Framework and/or .NET Standard 2.0 targets.
+ bool isDynamicCodeSupported = true;
+#endif
+ if (!isDynamicCodeSupported)
+ {
+ reason = "Dynamic code not supported";
+ return false;
+ }
+
+ var iHostedServiceType = Type.GetType(
+ "Microsoft.Extensions.Hosting.IHostedService, Microsoft.Extensions.Hosting.Abstractions", throwOnError: false);
+
+ if (iHostedServiceType == null)
+ {
+ reason = "Microsoft.Extensions.Hosting.IHostedService not found";
+ return false;
+ }
+
+ lock (LockObject)
+ {
+ if (!initialized)
+ {
+ try
+ {
+ hostedServiceImplementation = CreateHostedServiceImplementation(iHostedServiceType);
+ }
+ catch (Exception ex)
+ {
+ OpenTelemetrySdkEventSource.Log.HostedServiceRegistrationFailure(ex);
+ }
+ finally
+ {
+ initialized = true;
+ }
+ }
+ }
+
+ if (hostedServiceImplementation == null)
+ {
+ reason = "Initialization failure";
+ return false;
+ }
+
+ services.TryAddSingleton();
+ services.TryAddEnumerable(ServiceDescriptor.Singleton(iHostedServiceType, hostedServiceImplementation));
+
+ reason = null;
+ return true;
+ }
+
+ private static Type CreateHostedServiceImplementation(Type iHostedServiceType)
+ {
+ /*
+ * Note: This code builds a class dynamically that does this...
+ *
+ * namespace OpenTelemetry.Extensions.Hosting.Implementation;
+ *
+ * class TelemetryHostedService : IHostedService
+ * {
+ * private readonly TelemetryHostedServiceHelper telemetryHostedServiceHelper;
+ *
+ * public TelemetryHostedService(TelemetryHostedServiceHelper telemetryHostedServiceHelper)
+ * {
+ * this.telemetryHostedServiceHelper = telemetryHostedServiceHelper;
+ * }
+ *
+ * public Task StartAsync(CancellationToken cancellationToken)
+ * {
+ * this.telemetryHostedServiceHelper.Start();
+ * return Task.CompletedTask;
+ * }
+ *
+ * public Task StopAsync(CancellationToken cancellationToken)
+ * {
+ * return Task.CompletedTask;
+ * }
+ * }
+ */
+
+ var getCompletedTaskMethod = typeof(Task).GetProperty(nameof(Task.CompletedTask), BindingFlags.Static | BindingFlags.Public)?.GetMethod
+ ?? throw new InvalidOperationException("Task.CompletedTask could not be found reflectively.");
+
+ // Note: It is important that the assembly is named
+ // OpenTelemetry.Extensions.Hosting and the type is named
+ // OpenTelemetry.Extensions.Hosting.Implementation.TelemetryHostedService
+ // to preserve compatibility with Azure Functions:
+ // https://github.com/Azure/azure-functions-host/blob/d4655cc4fbb34fc14e6861731991118a9acd02ed/src/WebJobs.Script.WebHost/DependencyInjection/DependencyValidator/DependencyValidator.cs#L57.
+ var assemblyName = new AssemblyName("OpenTelemetry.Extensions.Hosting");
+
+ assemblyName.SetPublicKey(typeof(HostingHelper).Assembly.GetName().GetPublicKey());
+
+ var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+
+ // Note: We use IgnoresAccessChecksToAttribute to allow the dynamic
+ // assembly to call TelemetryHostedService which is internal to
+ // OpenTelemetry.dll.
+ var ignoresAccessChecksTo = new CustomAttributeBuilder(
+ typeof(IgnoresAccessChecksToAttribute).GetConstructor(new Type[] { typeof(string) }) ?? throw new InvalidOperationException("IgnoresAccessChecksToAttribute constructor could not be found reflectively."),
+ new object[] { typeof(TelemetryHostedServiceHelper).Assembly.GetName().Name! });
+
+ assemblyBuilder.SetCustomAttribute(ignoresAccessChecksTo);
+
+ var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name!);
+
+ var typeBuilder = moduleBuilder.DefineType("OpenTelemetry.Extensions.Hosting.Implementation.TelemetryHostedService", TypeAttributes.NotPublic);
+
+ typeBuilder.AddInterfaceImplementation(iHostedServiceType);
+
+ var hostedServiceImplementationField = typeBuilder.DefineField(
+ "telemetryHostedServiceHelper",
+ typeof(TelemetryHostedServiceHelper),
+ FieldAttributes.Private | FieldAttributes.InitOnly);
+
+ var constructor = typeBuilder.DefineConstructor(
+ MethodAttributes.Public,
+ CallingConventions.Standard,
+ new Type[] { typeof(TelemetryHostedServiceHelper) });
+
+ var constructorGenerator = constructor.GetILGenerator();
+
+ constructorGenerator.Emit(OpCodes.Ldarg_0);
+ constructorGenerator.Emit(
+ OpCodes.Call,
+ typeof(object).GetConstructor(Type.EmptyTypes) ?? throw new InvalidOperationException("Object constructor could not be found reflectively."));
+ constructorGenerator.Emit(OpCodes.Ldarg_0);
+ constructorGenerator.Emit(OpCodes.Ldarg_1);
+ constructorGenerator.Emit(OpCodes.Stfld, hostedServiceImplementationField);
+ constructorGenerator.Emit(OpCodes.Ret);
+
+ var startAsyncMethodBuilder = typeBuilder.DefineMethod(
+ "StartAsync",
+ MethodAttributes.Public | MethodAttributes.Virtual,
+ typeof(Task),
+ new Type[] { typeof(CancellationToken) });
+
+ var startAsyncMethodGenerator = startAsyncMethodBuilder.GetILGenerator();
+
+ startAsyncMethodGenerator.Emit(OpCodes.Ldarg_0);
+ startAsyncMethodGenerator.Emit(OpCodes.Ldfld, hostedServiceImplementationField);
+ startAsyncMethodGenerator.Emit(
+ OpCodes.Call,
+ typeof(TelemetryHostedServiceHelper).GetMethod(nameof(TelemetryHostedServiceHelper.Start)) ?? throw new InvalidOperationException($"{nameof(TelemetryHostedServiceHelper)}.{nameof(TelemetryHostedServiceHelper.Start)} could not be found reflectively."));
+ startAsyncMethodGenerator.Emit(OpCodes.Call, getCompletedTaskMethod);
+ startAsyncMethodGenerator.Emit(OpCodes.Ret);
+
+ typeBuilder.DefineMethodOverride(
+ startAsyncMethodBuilder,
+ iHostedServiceType.GetMethod("StartAsync") ?? throw new InvalidOperationException("IHostedService.StartAsync could not be found reflectively."));
+
+ var stopAsyncMethodBuilder = typeBuilder.DefineMethod(
+ "StopAsync",
+ MethodAttributes.Public | MethodAttributes.Virtual,
+ typeof(Task),
+ new Type[] { typeof(CancellationToken) });
+
+ var stopAsyncMethodGenerator = stopAsyncMethodBuilder.GetILGenerator();
+
+ stopAsyncMethodGenerator.Emit(OpCodes.Call, getCompletedTaskMethod);
+ stopAsyncMethodGenerator.Emit(OpCodes.Ret);
+
+ typeBuilder.DefineMethodOverride(
+ stopAsyncMethodBuilder,
+ iHostedServiceType.GetMethod("StopAsync") ?? throw new InvalidOperationException("IHostedService.StopAsync could not be found reflectively."));
+
+#if !NETSTANDARD2_0
+ return typeBuilder.CreateType()
+#else
+ return typeBuilder.CreateTypeInfo()
+#endif
+ ?? throw new InvalidOperationException("IHostedService implementation could not be created dynamically.");
+ }
+
+ private sealed class TelemetryHostedServiceHelper
+ {
+ private readonly IServiceProvider serviceProvider;
+
+ public TelemetryHostedServiceHelper(IServiceProvider serviceProvider)
+ {
+ Debug.Assert(serviceProvider != null, "serviceProvider was null");
+
+ this.serviceProvider = serviceProvider!;
+ }
+
+ public void Start()
+ {
+ var serviceProvider = this.serviceProvider;
+
+ var meterProvider = serviceProvider.GetService();
+ if (meterProvider == null)
+ {
+ OpenTelemetrySdkEventSource.Log.MeterProviderNotRegistered();
+ }
+
+ var tracerProvider = serviceProvider.GetService();
+ if (tracerProvider == null)
+ {
+ OpenTelemetrySdkEventSource.Log.TracerProviderNotRegistered();
+ }
+ }
+ }
+}
diff --git a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs
index 848737de80f..68a756d0d7b 100644
--- a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs
+++ b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs
@@ -175,6 +175,15 @@ public void DroppedExportProcessorItems(string exportProcessorName, string expor
}
}
+ [NonEvent]
+ public void HostedServiceRegistrationFailure(Exception ex)
+ {
+ if (this.IsEnabled(EventLevel.Error, EventKeywords.All))
+ {
+ this.HostedServiceRegistrationFailure(ex.ToInvariantString());
+ }
+ }
+
[Event(1, Message = "Span processor queue size reached maximum. Throttling spans.", Level = EventLevel.Warning)]
public void SpanProcessorQueueIsExhausted()
{
@@ -415,6 +424,36 @@ public void InvalidEnvironmentVariable(string key, string value)
this.WriteEvent(47, key, value);
}
+ [Event(48, Message = "OpenTelemetry IHostedService registered in application services.", Level = EventLevel.Informational)]
+ public void HostedServiceRegistered()
+ {
+ this.WriteEvent(48);
+ }
+
+ [Event(49, Message = "OpenTelemetry IHostedService application services registration skipped. Reason: '{0}'", Level = EventLevel.Warning)]
+ public void HostedServiceRegistrationSkipped(string reason)
+ {
+ this.WriteEvent(49, reason);
+ }
+
+ [Event(50, Message = "OpenTelemetry IHostedService could not be registered in application services. Error: '{0}'", Level = EventLevel.Error)]
+ public void HostedServiceRegistrationFailure(string error)
+ {
+ this.WriteEvent(50, error);
+ }
+
+ [Event(51, Message = "OpenTelemetry TracerProvider was not found in application services. Tracing will remain disabled.", Level = EventLevel.Warning)]
+ public void TracerProviderNotRegistered()
+ {
+ this.WriteEvent(51);
+ }
+
+ [Event(52, Message = "OpenTelemetry MeterProvider was not found in application services. Metrics will remain disabled.", Level = EventLevel.Warning)]
+ public void MeterProviderNotRegistered()
+ {
+ this.WriteEvent(52);
+ }
+
#if DEBUG
public class OpenTelemetryEventListener : EventListener
{
diff --git a/src/OpenTelemetry/Internal/Shims/IgnoresAccessChecksToAttribute.cs b/src/OpenTelemetry/Internal/Shims/IgnoresAccessChecksToAttribute.cs
new file mode 100644
index 00000000000..d4fee58cfbd
--- /dev/null
+++ b/src/OpenTelemetry/Internal/Shims/IgnoresAccessChecksToAttribute.cs
@@ -0,0 +1,33 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#nullable enable
+
+namespace System.Runtime.CompilerServices;
+
+///
+/// IgnoresAccessChecksToAttribute tells the runtime to bypass visibility checks
+/// to some assembly. See: .
+///
+[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+internal sealed class IgnoresAccessChecksToAttribute : Attribute
+{
+ public IgnoresAccessChecksToAttribute(string assemblyName)
+ => this.AssemblyName = assemblyName;
+
+ public string AssemblyName { get; }
+}
diff --git a/src/OpenTelemetry/OpenTelemetry.csproj b/src/OpenTelemetry/OpenTelemetry.csproj
index 65e87e8f969..5decd71ff36 100644
--- a/src/OpenTelemetry/OpenTelemetry.csproj
+++ b/src/OpenTelemetry/OpenTelemetry.csproj
@@ -20,6 +20,7 @@
+
diff --git a/src/OpenTelemetry/OpenTelemetryBuilder.cs b/src/OpenTelemetry/OpenTelemetryBuilder.cs
index f817e0bfe68..216343c9f60 100644
--- a/src/OpenTelemetry/OpenTelemetryBuilder.cs
+++ b/src/OpenTelemetry/OpenTelemetryBuilder.cs
@@ -74,18 +74,9 @@ public OpenTelemetryBuilder ConfigureResource(
/// Adds metric services into the builder.
///
///
- /// Notes:
- ///
- /// - A will not be created automatically
- /// using this method. To begin collecting metrics either use the
- /// OpenTelemetryBuilder.StartWithHost extension in the
- /// OpenTelemetry.Extensions.Hosting package or access the through the application .
- /// - This is safe to be called multiple times and by library authors.
+ /// Note: This is safe to be called multiple times and by library authors.
/// Only a single will be created for a given
- /// .
- ///
+ /// .
///
/// The supplied for chaining
/// calls.
@@ -115,18 +106,9 @@ public OpenTelemetryBuilder WithMetrics(Action configure)
/// Adds tracing services into the builder.
///
///
- /// Notes:
- ///
- /// - A will not be created automatically
- /// using this method. To begin collecting traces either use the
- /// OpenTelemetryBuilder.StartWithHost extension in the
- /// OpenTelemetry.Extensions.Hosting package or access the through the application .
- /// - This is safe to be called multiple times and by library authors.
+ /// Note: This is safe to be called multiple times and by library authors.
/// Only a single will be created for a given
- /// .
- ///
+ /// .
///
/// The supplied for chaining
/// calls.
diff --git a/src/OpenTelemetry/OpenTelemetryServiceCollectionExtensions.cs b/src/OpenTelemetry/OpenTelemetryServiceCollectionExtensions.cs
index 2541a85f7bb..0fc0f408976 100644
--- a/src/OpenTelemetry/OpenTelemetryServiceCollectionExtensions.cs
+++ b/src/OpenTelemetry/OpenTelemetryServiceCollectionExtensions.cs
@@ -17,6 +17,7 @@
#nullable enable
using Microsoft.Extensions.DependencyInjection;
+using OpenTelemetry.Internal;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
@@ -35,12 +36,12 @@ public static class OpenTelemetryServiceCollectionExtensions
/// Notes:
///
/// - A and/or
- /// will not be created automatically using this method. To begin collecting
- /// traces and/or metrics either use the
- /// OpenTelemetryBuilder.StartWithHost extension in the
- /// OpenTelemetry.Extensions.Hosting package or access the and/or through the
- /// application .
+ /// will be created automatically using this method if a host supporting
+ /// Microsoft.Extensions.Hosting.IHostedService is detected at
+ /// runtime. To begin collecting traces and/or metrics when hosting
+ /// extensions are not being used access the
+ /// and/or through the application .
/// - This is safe to be called multiple times and by library authors.
/// Only a single and/or will be created for a given The supplied for chaining
/// calls.
public static OpenTelemetryBuilder AddOpenTelemetry(this IServiceCollection services)
- => new(services);
+ {
+ HostingHelper.AddOpenTelemetryHostedServiceIntoServiceCollection(services);
+
+ return new(services);
+ }
}
diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/EventSourceTest.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/EventSourceTest.cs
deleted file mode 100644
index 64b4ab634bf..00000000000
--- a/test/OpenTelemetry.Extensions.Hosting.Tests/EventSourceTest.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using OpenTelemetry.Extensions.Hosting.Implementation;
-using OpenTelemetry.Tests;
-using Xunit;
-
-namespace OpenTelemetry.Extensions.Hosting.Tests
-{
- public class EventSourceTest
- {
- [Fact]
- public void EventSourceTest_HostingExtensionsEventSource()
- {
- EventSourceTestHelper.MethodsAreImplementedConsistentlyWithTheirAttributes(HostingExtensionsEventSource.Log);
- }
- }
-}
diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs
deleted file mode 100644
index fe267d558a5..00000000000
--- a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using OpenTelemetry.Metrics;
-using Xunit;
-
-namespace OpenTelemetry.Extensions.Hosting.Tests
-{
- public class HostingMeterExtensionTests
- {
- [Fact]
- public async Task AddOpenTelemetry_StartWithHost_CreationAndDisposal()
- {
- var callbackRun = false;
-
- var builder = new HostBuilder().ConfigureServices(services =>
- {
- services.AddOpenTelemetry()
- .WithMetrics(builder => builder
- .AddInstrumentation(() =>
- {
- callbackRun = true;
- return new object();
- }))
- .StartWithHost();
- });
-
- var host = builder.Build();
-
- Assert.False(callbackRun);
-
- await host.StartAsync().ConfigureAwait(false);
-
- Assert.True(callbackRun);
-
- await host.StopAsync().ConfigureAwait(false);
-
- Assert.True(callbackRun);
-
- host.Dispose();
-
- Assert.True(callbackRun);
- }
-
- [Fact]
- public async Task AddOpenTelemetry_StartWithHost_HostConfigurationHonoredTest()
- {
- bool configureBuilderCalled = false;
-
- var builder = new HostBuilder()
- .ConfigureAppConfiguration(builder =>
- {
- builder.AddInMemoryCollection(new Dictionary
- {
- ["TEST_KEY"] = "TEST_KEY_VALUE",
- });
- })
- .ConfigureServices(services =>
- {
- services.AddOpenTelemetry()
- .WithMetrics(builder =>
- {
- if (builder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder)
- {
- deferredMeterProviderBuilder.Configure((sp, builder) =>
- {
- configureBuilderCalled = true;
-
- var configuration = sp.GetRequiredService();
-
- var testKeyValue = configuration.GetValue("TEST_KEY", null);
-
- Assert.Equal("TEST_KEY_VALUE", testKeyValue);
- });
- }
- })
- .StartWithHost();
- });
-
- var host = builder.Build();
-
- Assert.False(configureBuilderCalled);
-
- await host.StartAsync().ConfigureAwait(false);
-
- Assert.True(configureBuilderCalled);
-
- await host.StopAsync().ConfigureAwait(false);
-
- host.Dispose();
- }
- }
-}
diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs
deleted file mode 100644
index 1122a9a8e86..00000000000
--- a/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using OpenTelemetry.Trace;
-using Xunit;
-
-namespace OpenTelemetry.Extensions.Hosting.Tests
-{
- public class HostingTracerExtensionTests
- {
- [Fact]
- public async Task AddOpenTelemetry_StartWithHost_CreationAndDisposal()
- {
- var callbackRun = false;
-
- var builder = new HostBuilder().ConfigureServices(services =>
- {
- services.AddOpenTelemetry()
- .WithTracing(builder => builder
- .AddInstrumentation(() =>
- {
- callbackRun = true;
- return new object();
- }))
- .StartWithHost();
- });
-
- var host = builder.Build();
-
- Assert.False(callbackRun);
-
- await host.StartAsync().ConfigureAwait(false);
-
- Assert.True(callbackRun);
-
- await host.StopAsync().ConfigureAwait(false);
-
- Assert.True(callbackRun);
-
- host.Dispose();
-
- Assert.True(callbackRun);
- }
-
- [Fact]
- public async Task AddOpenTelemetry_StartWithHost_HostConfigurationHonoredTest()
- {
- bool configureBuilderCalled = false;
-
- var builder = new HostBuilder()
- .ConfigureAppConfiguration(builder =>
- {
- builder.AddInMemoryCollection(new Dictionary
- {
- ["TEST_KEY"] = "TEST_KEY_VALUE",
- });
- })
- .ConfigureServices(services =>
- {
- services.AddOpenTelemetry()
- .WithTracing(builder =>
- {
- if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
- {
- deferredTracerProviderBuilder.Configure((sp, builder) =>
- {
- configureBuilderCalled = true;
-
- var configuration = sp.GetRequiredService();
-
- var testKeyValue = configuration.GetValue("TEST_KEY", null);
-
- Assert.Equal("TEST_KEY_VALUE", testKeyValue);
- });
- }
- })
- .StartWithHost();
- });
-
- var host = builder.Build();
-
- Assert.False(configureBuilderCalled);
-
- await host.StartAsync().ConfigureAwait(false);
-
- Assert.True(configureBuilderCalled);
-
- await host.StopAsync().ConfigureAwait(false);
-
- host.Dispose();
- }
- }
-}
diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs
index f32a85aedf3..cb8d05ab9ad 100644
--- a/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs
+++ b/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs
@@ -16,11 +16,8 @@
#if NET6_0_OR_GREATER
-using System;
-using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Net;
-using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@@ -89,7 +86,7 @@ private static async Task RunMetricsTest(Action configure,
using var host = await new HostBuilder()
.ConfigureWebHost(webBuilder => webBuilder
.UseTestServer()
- .ConfigureServices(services => services.AddOpenTelemetry().WithMetrics(configure).StartWithHost())
+ .ConfigureServices(services => services.AddOpenTelemetry().WithMetrics(configure))
.Configure(app => app.Run(httpContext =>
{
testAction.Invoke();
diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/TelemetryHostedServiceTests.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/TelemetryHostedServiceTests.cs
deleted file mode 100644
index 3900a74028f..00000000000
--- a/test/OpenTelemetry.Extensions.Hosting.Tests/TelemetryHostedServiceTests.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-using 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 =>
- {
- if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
- {
- deferredTracerProviderBuilder.Configure((sp, sdkBuilder) =>
- {
- try
- {
- // Note: This throws because services cannot be
- // registered after IServiceProvider has been
- // created.
- sdkBuilder.SetSampler();
- }
- catch (NotSupportedException)
- {
- expectedInnerExceptionThrown = true;
- throw;
- }
- });
- }
- })
- .StartWithHost();
- });
-
- var host = builder.Build();
-
- await Assert.ThrowsAsync(() => 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);
- }
-}
diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs
index cc7ffcee3c4..cb51bd437c4 100644
--- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs
+++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs
@@ -653,8 +653,7 @@ public async Task ActivitiesStartedInMiddlewareBySettingHostActivityToNullShould
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
.AddSource(activitySourceName)
- .AddInMemoryExporter(exportedItems))
- .StartWithHost();
+ .AddInMemoryExporter(exportedItems));
});
builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders());
})
@@ -692,8 +691,7 @@ void ConfigureTestServices(IServiceCollection services)
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
- .AddInMemoryExporter(exportedItems))
- .StartWithHost();
+ .AddInMemoryExporter(exportedItems));
// Register ActivitySource here so that it will be used
// by ASP.NET Core to create activities
diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs
index 16136110509..3631ca9a1ef 100644
--- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs
+++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs
@@ -46,8 +46,7 @@ void ConfigureTestServices(IServiceCollection services)
{
services.AddOpenTelemetry()
.WithTracing(builder => builder
- .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null))
- .StartWithHost();
+ .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null));
services.Configure(name, options =>
{
@@ -78,8 +77,7 @@ void ConfigureTestServices(IServiceCollection services)
{
services.AddOpenTelemetry()
.WithMetrics(builder => builder
- .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null))
- .StartWithHost();
+ .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null));
services.Configure(name, options =>
{
diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs
index 971920474e9..8500ac00a22 100644
--- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs
+++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs
@@ -63,8 +63,7 @@ public async Task SuccessfulTemplateControllerCallGeneratesASpan(
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation(options => options.RecordException = recordException)
- .AddInMemoryExporter(exportedItems))
- .StartWithHost();
+ .AddInMemoryExporter(exportedItems));
});
builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders());
})
diff --git a/test/OpenTelemetry.Tests/OpenTelemetry.Tests.csproj b/test/OpenTelemetry.Tests/OpenTelemetry.Tests.csproj
index c87707d50eb..c2db74d6d20 100644
--- a/test/OpenTelemetry.Tests/OpenTelemetry.Tests.csproj
+++ b/test/OpenTelemetry.Tests/OpenTelemetry.Tests.csproj
@@ -16,7 +16,8 @@
-
+
+
diff --git a/test/OpenTelemetry.Tests/OpenTelemetryServiceCollectionExtensionsTests.cs b/test/OpenTelemetry.Tests/OpenTelemetryServiceCollectionExtensionsTests.cs
new file mode 100644
index 00000000000..fa425c2d470
--- /dev/null
+++ b/test/OpenTelemetry.Tests/OpenTelemetryServiceCollectionExtensionsTests.cs
@@ -0,0 +1,264 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#nullable enable
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Trace;
+using Xunit;
+
+namespace OpenTelemetry.Tests;
+
+public class OpenTelemetryServiceCollectionExtensionsTests
+{
+ [Fact]
+ public void AddOpenTelemetry_HostedService_Registered()
+ {
+ var services = new ServiceCollection();
+
+ services.AddOpenTelemetry();
+
+ using var serviceProvider = services.BuildServiceProvider();
+
+ var hostedServices = serviceProvider.GetServices();
+
+ Assert.NotEmpty(hostedServices);
+ }
+
+ [Fact]
+ public async Task AddOpenTelemetry_HostedService_WithoutProvidersDoesNotThrow()
+ {
+ var builder = new HostBuilder().ConfigureServices(services =>
+ {
+ services.AddOpenTelemetry();
+ });
+
+ var host = builder.Build();
+
+ await host.StartAsync().ConfigureAwait(false);
+
+ await host.StopAsync().ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task AddOpenTelemetry_HostedService_StartWithExceptionsThrows()
+ {
+ bool expectedInnerExceptionThrown = false;
+
+ var builder = new HostBuilder().ConfigureServices(services =>
+ {
+ services.AddOpenTelemetry()
+ .WithTracing(builder =>
+ {
+ if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
+ {
+ deferredTracerProviderBuilder.Configure((sp, sdkBuilder) =>
+ {
+ try
+ {
+ // Note: This throws because services cannot be
+ // registered after IServiceProvider has been
+ // created.
+ sdkBuilder.SetSampler();
+ }
+ catch (NotSupportedException)
+ {
+ expectedInnerExceptionThrown = true;
+ throw;
+ }
+ });
+ }
+ });
+ });
+
+ var host = builder.Build();
+
+ await Assert.ThrowsAsync(() => host.StartAsync()).ConfigureAwait(false);
+
+ await host.StopAsync().ConfigureAwait(false);
+
+ Assert.True(expectedInnerExceptionThrown);
+ }
+
+ [Fact]
+ public async Task AddOpenTelemetry_WithMetrics_CreationAndDisposal()
+ {
+ var callbackRun = false;
+
+ var builder = new HostBuilder().ConfigureServices(services =>
+ {
+ services.AddOpenTelemetry()
+ .WithMetrics(builder => builder
+ .AddInstrumentation(() =>
+ {
+ callbackRun = true;
+ return new object();
+ }));
+ });
+
+ var host = builder.Build();
+
+ Assert.False(callbackRun);
+
+ await host.StartAsync().ConfigureAwait(false);
+
+ Assert.True(callbackRun);
+
+ await host.StopAsync().ConfigureAwait(false);
+
+ Assert.True(callbackRun);
+
+ host.Dispose();
+
+ Assert.True(callbackRun);
+ }
+
+ [Fact]
+ public async Task AddOpenTelemetry_WithMetrics_HostConfigurationHonoredTest()
+ {
+ bool configureBuilderCalled = false;
+
+ var builder = new HostBuilder()
+ .ConfigureAppConfiguration(builder =>
+ {
+ builder.AddInMemoryCollection(new Dictionary
+ {
+ ["TEST_KEY"] = "TEST_KEY_VALUE",
+ });
+ })
+ .ConfigureServices(services =>
+ {
+ services.AddOpenTelemetry()
+ .WithMetrics(builder =>
+ {
+ if (builder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder)
+ {
+ deferredMeterProviderBuilder.Configure((sp, builder) =>
+ {
+ configureBuilderCalled = true;
+
+ var configuration = sp.GetRequiredService();
+
+ var testKeyValue = configuration.GetValue("TEST_KEY", null);
+
+ Assert.Equal("TEST_KEY_VALUE", testKeyValue);
+ });
+ }
+ });
+ });
+
+ var host = builder.Build();
+
+ Assert.False(configureBuilderCalled);
+
+ await host.StartAsync().ConfigureAwait(false);
+
+ Assert.True(configureBuilderCalled);
+
+ await host.StopAsync().ConfigureAwait(false);
+
+ host.Dispose();
+ }
+
+ [Fact]
+ public async Task AddOpenTelemetry_WithTracing_CreationAndDisposal()
+ {
+ var callbackRun = false;
+
+ var builder = new HostBuilder().ConfigureServices(services =>
+ {
+ services.AddOpenTelemetry()
+ .WithTracing(builder => builder
+ .AddInstrumentation(() =>
+ {
+ callbackRun = true;
+ return new object();
+ }));
+ });
+
+ var host = builder.Build();
+
+ Assert.False(callbackRun);
+
+ await host.StartAsync().ConfigureAwait(false);
+
+ Assert.True(callbackRun);
+
+ await host.StopAsync().ConfigureAwait(false);
+
+ Assert.True(callbackRun);
+
+ host.Dispose();
+
+ Assert.True(callbackRun);
+ }
+
+ [Fact]
+ public async Task AddOpenTelemetry_WithTracing_HostConfigurationHonoredTest()
+ {
+ bool configureBuilderCalled = false;
+
+ var builder = new HostBuilder()
+ .ConfigureAppConfiguration(builder =>
+ {
+ builder.AddInMemoryCollection(new Dictionary
+ {
+ ["TEST_KEY"] = "TEST_KEY_VALUE",
+ });
+ })
+ .ConfigureServices(services =>
+ {
+ services.AddOpenTelemetry()
+ .WithTracing(builder =>
+ {
+ if (builder is IDeferredTracerProviderBuilder deferredTracerProviderBuilder)
+ {
+ deferredTracerProviderBuilder.Configure((sp, builder) =>
+ {
+ configureBuilderCalled = true;
+
+ var configuration = sp.GetRequiredService();
+
+ var testKeyValue = configuration.GetValue("TEST_KEY", null);
+
+ Assert.Equal("TEST_KEY_VALUE", testKeyValue);
+ });
+ }
+ });
+ });
+
+ var host = builder.Build();
+
+ Assert.False(configureBuilderCalled);
+
+ await host.StartAsync().ConfigureAwait(false);
+
+ Assert.True(configureBuilderCalled);
+
+ await host.StopAsync().ConfigureAwait(false);
+
+ host.Dispose();
+ }
+
+ private sealed class MySampler : Sampler
+ {
+ public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
+ => new SamplingResult(SamplingDecision.RecordAndSample);
+ }
+}