[.NET7.0] AspNetCore ActivitySource Migration (#3391)
This commit is contained in:
parent
8dd0743174
commit
e24677b8ea
|
|
@ -35,6 +35,10 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
|||
internal class HttpInListener : ListenerHandler
|
||||
{
|
||||
internal const string ActivityOperationName = "Microsoft.AspNetCore.Hosting.HttpRequestIn";
|
||||
#if NET7_0_OR_GREATER
|
||||
// https://github.com/dotnet/aspnetcore/blob/8d6554e655b64da75b71e0e20d6db54a3ba8d2fb/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs#L85
|
||||
internal static readonly string AspNetCoreActivitySourceName = "Microsoft.AspNetCore";
|
||||
#endif
|
||||
internal static readonly AssemblyName AssemblyName = typeof(HttpInListener).Assembly.GetName();
|
||||
internal static readonly string ActivitySourceName = AssemblyName.Name;
|
||||
internal static readonly Version Version = AssemblyName.Version;
|
||||
|
|
@ -96,8 +100,14 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
|||
// Create a new activity with its parent set from the extracted context.
|
||||
// This makes the new activity as a "sibling" of the activity created by
|
||||
// Asp.Net Core.
|
||||
#if NET7_0_OR_GREATER
|
||||
// For NET7.0 onwards activity is created using ActivitySource so,
|
||||
// we will use the source of the activity to create the new one.
|
||||
Activity newOne = activity.Source.CreateActivity(ActivityOperationName, ActivityKind.Server, ctx.ActivityContext);
|
||||
#else
|
||||
Activity newOne = new Activity(ActivityOperationName);
|
||||
newOne.SetParentId(ctx.ActivityContext.TraceId, ctx.ActivityContext.SpanId, ctx.ActivityContext.TraceFlags);
|
||||
#endif
|
||||
newOne.TraceStateString = ctx.ActivityContext.TraceState;
|
||||
|
||||
newOne.SetTag("IsCreatedByInstrumentation", bool.TrueString);
|
||||
|
|
@ -135,8 +145,10 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
|||
return;
|
||||
}
|
||||
|
||||
#if !NET7_0_OR_GREATER
|
||||
ActivityInstrumentationHelper.SetActivitySourceProperty(activity, ActivitySource);
|
||||
ActivityInstrumentationHelper.SetKindProperty(activity, ActivityKind.Server);
|
||||
#endif
|
||||
|
||||
var path = (request.PathBase.HasValue || request.Path.HasValue) ? (request.PathBase + request.Path).ToString() : "/";
|
||||
activity.DisplayName = path;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@
|
|||
// </copyright>
|
||||
|
||||
using System;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
#endif
|
||||
using OpenTelemetry.Instrumentation.AspNetCore;
|
||||
using OpenTelemetry.Instrumentation.AspNetCore.Implementation;
|
||||
using OpenTelemetry.Internal;
|
||||
|
|
@ -42,7 +46,7 @@ namespace OpenTelemetry.Trace
|
|||
{
|
||||
return deferredTracerProviderBuilder.Configure((sp, builder) =>
|
||||
{
|
||||
AddAspNetCoreInstrumentation(builder, sp.GetOptions<AspNetCoreInstrumentationOptions>(), configureAspNetCoreInstrumentationOptions);
|
||||
AddAspNetCoreInstrumentation(builder, sp.GetOptions<AspNetCoreInstrumentationOptions>(), configureAspNetCoreInstrumentationOptions, sp);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -51,22 +55,44 @@ namespace OpenTelemetry.Trace
|
|||
|
||||
internal static TracerProviderBuilder AddAspNetCoreInstrumentation(
|
||||
this TracerProviderBuilder builder,
|
||||
AspNetCoreInstrumentation instrumentation)
|
||||
AspNetCoreInstrumentation instrumentation,
|
||||
IServiceProvider serviceProvider = null)
|
||||
{
|
||||
// For .NET7.0 onwards activity will be created using activitySource.
|
||||
// https://github.com/dotnet/aspnetcore/blob/bf3352f2422bf16fa3ca49021f0e31961ce525eb/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs#L327
|
||||
// For .NET6.0 and below, we will continue to use legacy way.
|
||||
#if NET7_0_OR_GREATER
|
||||
// TODO: Check with .NET team to see if this can be prevented
|
||||
// as this allows user to override the ActivitySource.
|
||||
var activitySourceService = serviceProvider?.GetService<ActivitySource>();
|
||||
if (activitySourceService != null)
|
||||
{
|
||||
builder.AddSource(activitySourceService.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For users not using hosting package?
|
||||
builder.AddSource(HttpInListener.AspNetCoreActivitySourceName);
|
||||
}
|
||||
#else
|
||||
builder.AddSource(HttpInListener.ActivitySourceName);
|
||||
builder.AddLegacySource(HttpInListener.ActivityOperationName); // for the activities created by AspNetCore
|
||||
#endif
|
||||
|
||||
return builder.AddInstrumentation(() => instrumentation);
|
||||
}
|
||||
|
||||
private static TracerProviderBuilder AddAspNetCoreInstrumentation(
|
||||
TracerProviderBuilder builder,
|
||||
AspNetCoreInstrumentationOptions options,
|
||||
Action<AspNetCoreInstrumentationOptions> configure = null)
|
||||
Action<AspNetCoreInstrumentationOptions> configure = null,
|
||||
IServiceProvider serviceProvider = null)
|
||||
{
|
||||
configure?.Invoke(options);
|
||||
return AddAspNetCoreInstrumentation(
|
||||
builder,
|
||||
new AspNetCoreInstrumentation(new HttpInListener(options)));
|
||||
new AspNetCoreInstrumentation(new HttpInListener(options)),
|
||||
serviceProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -348,7 +348,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
|
|||
var expectedTraceId = ActivityTraceId.CreateRandom();
|
||||
var expectedParentSpanId = ActivitySpanId.CreateRandom();
|
||||
var expectedTraceState = "rojo=1,congo=2";
|
||||
var activityContext = new ActivityContext(expectedTraceId, expectedParentSpanId, ActivityTraceFlags.Recorded, expectedTraceState);
|
||||
var activityContext = new ActivityContext(expectedTraceId, expectedParentSpanId, ActivityTraceFlags.Recorded, expectedTraceState, true);
|
||||
var expectedBaggage = Baggage.SetBaggage("key1", "value1").SetBaggage("key2", "value2");
|
||||
Sdk.SetDefaultTextMapPropagator(new ExtractOnlyPropagator(activityContext, expectedBaggage));
|
||||
|
||||
|
|
@ -586,6 +586,47 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
|
|||
Assert.Equal(activityName, middlewareActivity.DisplayName);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[Fact]
|
||||
public async Task UserRegisteredActivitySourceIsUsedForActivityCreationByAspNetCore()
|
||||
{
|
||||
var exportedItems = new List<Activity>();
|
||||
void ConfigureTestServices(IServiceCollection services)
|
||||
{
|
||||
services.AddOpenTelemetryTracing(options =>
|
||||
{
|
||||
options.AddAspNetCoreInstrumentation()
|
||||
.AddInMemoryExporter(exportedItems);
|
||||
});
|
||||
|
||||
// Register ActivitySource here so that it will be used
|
||||
// by ASP.NET Core to create activities
|
||||
// https://github.com/dotnet/aspnetcore/blob/0e5cbf447d329a1e7d69932c3decd1c70a00fbba/src/Hosting/Hosting/src/Internal/WebHost.cs#L152
|
||||
services.AddSingleton(sp => new ActivitySource("UserRegisteredActivitySource"));
|
||||
}
|
||||
|
||||
// Arrange
|
||||
using (var client = this.factory
|
||||
.WithWebHostBuilder(builder =>
|
||||
builder.ConfigureTestServices(ConfigureTestServices))
|
||||
.CreateClient())
|
||||
{
|
||||
// Act
|
||||
var response = await client.GetAsync("/api/values");
|
||||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode(); // Status Code 200-299
|
||||
|
||||
WaitForActivityExport(exportedItems, 1);
|
||||
}
|
||||
|
||||
Assert.Single(exportedItems);
|
||||
var activity = exportedItems[0];
|
||||
|
||||
Assert.Equal("UserRegisteredActivitySource", activity.Source.Name);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.tracerProvider?.Dispose();
|
||||
|
|
@ -608,8 +649,13 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
|
|||
private static void ValidateAspNetCoreActivity(Activity activityToValidate, string expectedHttpPath)
|
||||
{
|
||||
Assert.Equal(ActivityKind.Server, activityToValidate.Kind);
|
||||
#if NET7_0_OR_GREATER
|
||||
Assert.Equal(HttpInListener.AspNetCoreActivitySourceName, activityToValidate.Source.Name);
|
||||
Assert.Empty(activityToValidate.Source.Version);
|
||||
#else
|
||||
Assert.Equal(HttpInListener.ActivitySourceName, activityToValidate.Source.Name);
|
||||
Assert.Equal(HttpInListener.Version.ToString(), activityToValidate.Source.Version);
|
||||
#endif
|
||||
Assert.Equal(expectedHttpPath, activityToValidate.GetTagValue(SemanticConventions.AttributeHttpTarget) as string);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue