diff --git a/build/Common.props b/build/Common.props
index a1d08f1e37d..d47bf985f5e 100644
--- a/build/Common.props
+++ b/build/Common.props
@@ -37,8 +37,7 @@
[17.4.1]
[3.1.0,)
$(MicrosoftExtensionsDependencyInjectionPkgVer)
- [2.1.0,)
- $(MicrosoftExtensionsHostingPkgVer)
+ [2.1.0,)
[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 a2914077175..2feba0bd229 100644
--- a/docs/trace/getting-started-aspnetcore/Program.cs
+++ b/docs/trace/getting-started-aspnetcore/Program.cs
@@ -27,7 +27,8 @@
.AddService(serviceName: "OTel.NET Getting Started"))
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
- .AddConsoleExporter());
+ .AddConsoleExporter())
+ .StartWithHost();
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 321fbcd608b..1956f427004 100644
--- a/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj
+++ b/docs/trace/getting-started-aspnetcore/getting-started-aspnetcore.csproj
@@ -8,6 +8,7 @@
+
diff --git a/examples/AspNetCore/Examples.AspNetCore.csproj b/examples/AspNetCore/Examples.AspNetCore.csproj
index 7e29680340f..b8b09bcd9d4 100644
--- a/examples/AspNetCore/Examples.AspNetCore.csproj
+++ b/examples/AspNetCore/Examples.AspNetCore.csproj
@@ -10,6 +10,7 @@
+
diff --git a/examples/AspNetCore/Program.cs b/examples/AspNetCore/Program.cs
index 80527159685..53245406d57 100644
--- a/examples/AspNetCore/Program.cs
+++ b/examples/AspNetCore/Program.cs
@@ -44,7 +44,8 @@
// for manual instrumentation
appBuilder.Services.AddSingleton();
-// Configure OpenTelemetry tracing & metrics.
+// Configure OpenTelemetry tracing & metrics with auto-start using the
+// StartWithHost extension from OpenTelemetry.Extensions.Hosting.
appBuilder.Services.AddOpenTelemetry()
.ConfigureResource(configureResource)
.WithTracing(builder =>
@@ -126,7 +127,8 @@
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 7123737717a..2a9028e8650 100644
--- a/examples/GrpcService/Examples.GrpcService.csproj
+++ b/examples/GrpcService/Examples.GrpcService.csproj
@@ -16,6 +16,7 @@
+
diff --git a/examples/GrpcService/Startup.cs b/examples/GrpcService/Startup.cs
index 32d595ab63d..2c875eae04b 100644
--- a/examples/GrpcService/Startup.cs
+++ b/examples/GrpcService/Startup.cs
@@ -61,7 +61,8 @@ 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 d3966c26aa2..90e66783302 100644
--- a/examples/MicroserviceExample/WebApi/Startup.cs
+++ b/examples/MicroserviceExample/WebApi/Startup.cs
@@ -43,7 +43,8 @@ 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 5e1695e9c86..876450b7176 100644
--- a/examples/MicroserviceExample/WebApi/WebApi.csproj
+++ b/examples/MicroserviceExample/WebApi/WebApi.csproj
@@ -10,6 +10,7 @@
+
diff --git a/examples/MicroserviceExample/WorkerService/Program.cs b/examples/MicroserviceExample/WorkerService/Program.cs
index 75ad1223e16..665265cedd4 100644
--- a/examples/MicroserviceExample/WorkerService/Program.cs
+++ b/examples/MicroserviceExample/WorkerService/Program.cs
@@ -42,7 +42,8 @@ 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 29d72978cd5..926e55dd6fd 100644
--- a/examples/MicroserviceExample/WorkerService/WorkerService.csproj
+++ b/examples/MicroserviceExample/WorkerService/WorkerService.csproj
@@ -11,6 +11,7 @@
+
diff --git a/src/OpenTelemetry.Exporter.Jaeger/README.md b/src/OpenTelemetry.Exporter.Jaeger/README.md
index 643d9874819..411e3d40283 100644
--- a/src/OpenTelemetry.Exporter.Jaeger/README.md
+++ b/src/OpenTelemetry.Exporter.Jaeger/README.md
@@ -98,7 +98,8 @@ 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 177f9639443..369b6e1574e 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md
@@ -135,7 +135,8 @@ 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 e6676934961..6bcd236b5bb 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md
@@ -28,7 +28,8 @@ dotnet add package --prerelease OpenTelemetry.Exporter.Prometheus.AspNetCore
```csharp
services.AddOpenTelemetry()
.WithMetrics(builder => builder
- .AddPrometheusExporter());
+ .AddPrometheusExporter())
+ .StartWithHost();
```
* Or configure directly:
diff --git a/src/OpenTelemetry.Exporter.Zipkin/README.md b/src/OpenTelemetry.Exporter.Zipkin/README.md
index aa277b7fdc2..20d794c051d 100644
--- a/src/OpenTelemetry.Exporter.Zipkin/README.md
+++ b/src/OpenTelemetry.Exporter.Zipkin/README.md
@@ -87,7 +87,8 @@ 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 63141a61d05..dbee0f5b37d 100644
--- a/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry.Extensions.Hosting/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
@@ -1,5 +1,6 @@
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
@@ -7,5 +8,6 @@ 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 b31b6c4ccb3..8e7983ec511 100644
--- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
+++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md
@@ -2,12 +2,6 @@
## 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
new file mode 100644
index 00000000000..f6f86038cfe
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Hosting/Implementation/HostingExtensionsEventSource.cs
@@ -0,0 +1,41 @@
+//
+// 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
new file mode 100644
index 00000000000..78e50395b59
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Hosting/Implementation/TelemetryHostedService.cs
@@ -0,0 +1,64 @@
+//
+// 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
new file mode 100644
index 00000000000..646ca614f44
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetryBuilderHostingExtensions.cs
@@ -0,0 +1,54 @@
+//
+// 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 ce238c273f7..64e837fbf16 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) pattern instead. This method will be removed in a future version.")]
+ [Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() 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) pattern instead. This method will be removed in a future version.")]
+ [Obsolete("Use the AddOpenTelemetry().WithTracing(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection services, Action configure)
{
- services.AddOpenTelemetry().WithTracing(configure);
+ services.AddOpenTelemetry().WithTracing(configure).StartWithHost();
return services;
}
@@ -100,7 +100,7 @@ public static IServiceCollection AddOpenTelemetryTracing(this IServiceCollection
/// .
/// Supplied for chaining
/// calls.
- [Obsolete("Use the AddOpenTelemetry().WithMetrics(configure) pattern instead. This method will be removed in a future version.")]
+ [Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() 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) pattern instead. This method will be removed in a future version.")]
+ [Obsolete("Use the AddOpenTelemetry().WithMetrics(configure).StartWithHost() pattern instead. This method will be removed in a future version.")]
public static IServiceCollection AddOpenTelemetryMetrics(this IServiceCollection services, Action configure)
{
- services.AddOpenTelemetry().WithMetrics(configure);
+ services.AddOpenTelemetry().WithMetrics(configure).StartWithHost();
return services;
}
diff --git a/src/OpenTelemetry.Extensions.Hosting/README.md b/src/OpenTelemetry.Extensions.Hosting/README.md
index 59014925824..a1703580f07 100644
--- a/src/OpenTelemetry.Extensions.Hosting/README.md
+++ b/src/OpenTelemetry.Extensions.Hosting/README.md
@@ -21,6 +21,17 @@ 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
@@ -61,9 +72,10 @@ using OpenTelemetry.Trace;
var appBuilder = WebApplication.CreateBuilder(args);
-appBuilder.Services.AddOpenTelemetryTracing(builder => builder.AddConsoleExporter());
-
-appBuilder.Services.AddOpenTelemetryMetrics(builder => builder.AddConsoleExporter());
+appBuilder.Services.AddOpenTelemetry()
+ .WithTracing(builder => builder.AddConsoleExporter())
+ .WithMetrics(builder => builder.AddConsoleExporter())
+ .StartWithHost();
var app = appBuilder.Build();
diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/README.md b/src/OpenTelemetry.Instrumentation.AspNetCore/README.md
index fd535b1682c..59e489b8676 100644
--- a/src/OpenTelemetry.Instrumentation.AspNetCore/README.md
+++ b/src/OpenTelemetry.Instrumentation.AspNetCore/README.md
@@ -58,7 +58,8 @@ public void ConfigureServices(IServiceCollection services)
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
- .AddJaegerExporter());
+ .AddJaegerExporter())
+ .StartWithHost();
}
```
@@ -87,7 +88,8 @@ services.Configure(options =>
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
- .AddJaegerExporter());
+ .AddJaegerExporter())
+ .StartWithHost();
```
### Filter
@@ -110,7 +112,8 @@ services.AddOpenTelemetry()
// only collect telemetry about HTTP GET requests
return httpContext.Request.Method.Equals("GET");
})
- .AddJaegerExporter());
+ .AddJaegerExporter())
+ .StartWithHost();
```
It is important to note that this `Filter` option is specific to this
@@ -147,7 +150,8 @@ 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 bfb6dfbb701..62bb0853aea 100644
--- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md
+++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/README.md
@@ -120,7 +120,8 @@ 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 2b03fe7dcaa..9940288268f 100644
--- a/src/OpenTelemetry/CHANGELOG.md
+++ b/src/OpenTelemetry/CHANGELOG.md
@@ -5,10 +5,6 @@
* 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 02928d154d5..5b97e90ce77 100644
--- a/src/OpenTelemetry/Internal/EnvironmentVariables/EnvironmentVariablesExtensions.cs
+++ b/src/OpenTelemetry/Internal/EnvironmentVariables/EnvironmentVariablesExtensions.cs
@@ -4,24 +4,49 @@
#nullable enable
-using Microsoft.Extensions.Configuration;
+using System;
using Microsoft.Extensions.Configuration.EnvironmentVariables;
-namespace OpenTelemetry.Internal;
-
-///
-/// Extension methods for registering with .
-///
-internal static class EnvironmentVariablesExtensions
+namespace Microsoft.Extensions.Configuration
{
///
- /// Adds an that reads configuration values from environment variables.
+ /// Extension methods for registering with .
///
- /// The to add to.
- /// The .
- public static IConfigurationBuilder AddEnvironmentVariables(this IConfigurationBuilder configurationBuilder)
+ internal static class EnvironmentVariablesExtensions
{
- configurationBuilder.Add(new EnvironmentVariablesConfigurationSource());
- return 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);
}
}
diff --git a/src/OpenTelemetry/Internal/HostingHelper.cs b/src/OpenTelemetry/Internal/HostingHelper.cs
deleted file mode 100644
index 58708f0aad6..00000000000
--- a/src/OpenTelemetry/Internal/HostingHelper.cs
+++ /dev/null
@@ -1,253 +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.
-//
-
-#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 68a756d0d7b..848737de80f 100644
--- a/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs
+++ b/src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs
@@ -175,15 +175,6 @@ 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()
{
@@ -424,36 +415,6 @@ 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
deleted file mode 100644
index d4fee58cfbd..00000000000
--- a/src/OpenTelemetry/Internal/Shims/IgnoresAccessChecksToAttribute.cs
+++ /dev/null
@@ -1,33 +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.
-//
-
-#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 5decd71ff36..65e87e8f969 100644
--- a/src/OpenTelemetry/OpenTelemetry.csproj
+++ b/src/OpenTelemetry/OpenTelemetry.csproj
@@ -20,7 +20,6 @@
-
diff --git a/src/OpenTelemetry/OpenTelemetryBuilder.cs b/src/OpenTelemetry/OpenTelemetryBuilder.cs
index 216343c9f60..f817e0bfe68 100644
--- a/src/OpenTelemetry/OpenTelemetryBuilder.cs
+++ b/src/OpenTelemetry/OpenTelemetryBuilder.cs
@@ -74,9 +74,18 @@ public OpenTelemetryBuilder ConfigureResource(
/// Adds metric services into the builder.
///
///
- /// Note: This is safe to be called multiple times and by library authors.
+ /// 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.
/// Only a single will be created for a given
- /// .
+ /// .
+ ///
///
/// The supplied for chaining
/// calls.
@@ -106,9 +115,18 @@ public OpenTelemetryBuilder WithMetrics(Action configure)
/// Adds tracing services into the builder.
///
///
- /// Note: This is safe to be called multiple times and by library authors.
+ /// 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.
/// 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 0fc0f408976..2541a85f7bb 100644
--- a/src/OpenTelemetry/OpenTelemetryServiceCollectionExtensions.cs
+++ b/src/OpenTelemetry/OpenTelemetryServiceCollectionExtensions.cs
@@ -17,7 +17,6 @@
#nullable enable
using Microsoft.Extensions.DependencyInjection;
-using OpenTelemetry.Internal;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
@@ -36,12 +35,12 @@ public static class OpenTelemetryServiceCollectionExtensions
/// Notes:
///
/// - A and/or
- /// 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 .
+ /// 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 .
/// - 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)
- {
- HostingHelper.AddOpenTelemetryHostedServiceIntoServiceCollection(services);
-
- return new(services);
- }
+ => new(services);
}
diff --git a/test/OpenTelemetry.Extensions.Hosting.Tests/EventSourceTest.cs b/test/OpenTelemetry.Extensions.Hosting.Tests/EventSourceTest.cs
new file mode 100644
index 00000000000..64b4ab634bf
--- /dev/null
+++ b/test/OpenTelemetry.Extensions.Hosting.Tests/EventSourceTest.cs
@@ -0,0 +1,31 @@
+//
+// 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
new file mode 100644
index 00000000000..fe267d558a5
--- /dev/null
+++ b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingMeterExtensionTests.cs
@@ -0,0 +1,109 @@
+//
+// 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
new file mode 100644
index 00000000000..1122a9a8e86
--- /dev/null
+++ b/test/OpenTelemetry.Extensions.Hosting.Tests/HostingTracerExtensionTests.cs
@@ -0,0 +1,109 @@
+//
+// 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 cb8d05ab9ad..f32a85aedf3 100644
--- a/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs
+++ b/test/OpenTelemetry.Extensions.Hosting.Tests/InMemoryExporterMetricsExtensionsTests.cs
@@ -16,8 +16,11 @@
#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;
@@ -86,7 +89,7 @@ private static async Task RunMetricsTest(Action configure,
using var host = await new HostBuilder()
.ConfigureWebHost(webBuilder => webBuilder
.UseTestServer()
- .ConfigureServices(services => services.AddOpenTelemetry().WithMetrics(configure))
+ .ConfigureServices(services => services.AddOpenTelemetry().WithMetrics(configure).StartWithHost())
.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
new file mode 100644
index 00000000000..3900a74028f
--- /dev/null
+++ b/test/OpenTelemetry.Extensions.Hosting.Tests/TelemetryHostedServiceTests.cs
@@ -0,0 +1,87 @@
+//
+// 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 cb51bd437c4..cc7ffcee3c4 100644
--- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs
+++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs
@@ -653,7 +653,8 @@ public async Task ActivitiesStartedInMiddlewareBySettingHostActivityToNullShould
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
.AddSource(activitySourceName)
- .AddInMemoryExporter(exportedItems));
+ .AddInMemoryExporter(exportedItems))
+ .StartWithHost();
});
builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders());
})
@@ -691,7 +692,8 @@ void ConfigureTestServices(IServiceCollection services)
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
- .AddInMemoryExporter(exportedItems));
+ .AddInMemoryExporter(exportedItems))
+ .StartWithHost();
// 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 3631ca9a1ef..16136110509 100644
--- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs
+++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/DependencyInjectionConfigTests.cs
@@ -46,7 +46,8 @@ void ConfigureTestServices(IServiceCollection services)
{
services.AddOpenTelemetry()
.WithTracing(builder => builder
- .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null));
+ .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null))
+ .StartWithHost();
services.Configure(name, options =>
{
@@ -77,7 +78,8 @@ void ConfigureTestServices(IServiceCollection services)
{
services.AddOpenTelemetry()
.WithMetrics(builder => builder
- .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null));
+ .AddAspNetCoreInstrumentation(name, configureAspNetCoreInstrumentationOptions: null))
+ .StartWithHost();
services.Configure(name, options =>
{
diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs
index 8500ac00a22..971920474e9 100644
--- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs
+++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs
@@ -63,7 +63,8 @@ public async Task SuccessfulTemplateControllerCallGeneratesASpan(
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation(options => options.RecordException = recordException)
- .AddInMemoryExporter(exportedItems));
+ .AddInMemoryExporter(exportedItems))
+ .StartWithHost();
});
builder.ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders());
})
diff --git a/test/OpenTelemetry.Tests/OpenTelemetry.Tests.csproj b/test/OpenTelemetry.Tests/OpenTelemetry.Tests.csproj
index c2db74d6d20..c87707d50eb 100644
--- a/test/OpenTelemetry.Tests/OpenTelemetry.Tests.csproj
+++ b/test/OpenTelemetry.Tests/OpenTelemetry.Tests.csproj
@@ -16,8 +16,7 @@
-
-
+
diff --git a/test/OpenTelemetry.Tests/OpenTelemetryServiceCollectionExtensionsTests.cs b/test/OpenTelemetry.Tests/OpenTelemetryServiceCollectionExtensionsTests.cs
deleted file mode 100644
index fa425c2d470..00000000000
--- a/test/OpenTelemetry.Tests/OpenTelemetryServiceCollectionExtensionsTests.cs
+++ /dev/null
@@ -1,264 +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.
-//
-
-#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);
- }
-}