Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.TelemetryHttpModule() -
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModuleOptions
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModuleOptions.OnExceptionCallback.get -> System.Action<System.Diagnostics.Activity?, System.Web.HttpContextBase!, System.Exception!>?
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModuleOptions.OnExceptionCallback.set -> void
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModuleOptions.OnRequestStartedCallback.get -> System.Action<System.Diagnostics.Activity?, System.Web.HttpContextBase!>?
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModuleOptions.OnRequestStartedCallback.get -> System.Func<System.Web.HttpContextBase!, System.Diagnostics.ActivityContext, System.Diagnostics.Activity?>?
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModuleOptions.OnRequestStartedCallback.set -> void
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModuleOptions.OnRequestStoppedCallback.get -> System.Action<System.Diagnostics.Activity?, System.Web.HttpContextBase!>?
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModuleOptions.OnRequestStoppedCallback.set -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
using System.Web;
using OpenTelemetry.Context;
using OpenTelemetry.Context.Propagation;
using OpenTelemetry.Internal;
using OpenTelemetry.Trace;

namespace OpenTelemetry.Instrumentation.AspNet;

Expand All @@ -16,31 +14,15 @@ namespace OpenTelemetry.Instrumentation.AspNet;
/// </summary>
internal static class ActivityHelper
{
/// <summary>
/// <see cref="Activity.OperationName"/> for OpenTelemetry.Instrumentation.AspNet created <see cref="Activity"/> objects.
/// </summary>
internal const string AspNetActivityName = "Microsoft.AspNet.HttpReqIn";

/// <summary>
/// Key to store the state in HttpContext.
/// </summary>
internal const string ContextKey = "__AspnetOpenTelemetryInstrumentationContext__";

/// <summary>
/// OpenTelemetry.Instrumentation.AspNet <see cref="ActivitySource"/> name.
/// </summary>
internal const string AspNetSourceName = "OpenTelemetry.Instrumentation.AspNet";

internal static readonly object StartedButNotSampledObj = new();

private const string BaggageSlotName = "otel.baggage";
private static readonly Func<HttpRequestBase, string, IEnumerable<string>> HttpRequestHeaderValuesGetter = (request, name) => request.Headers.GetValues(name);
private static readonly ActivitySource AspNetSource = new(
AspNetSourceName,
typeof(ActivityHelper).Assembly.GetPackageVersion());

[ThreadStatic]
private static KeyValuePair<string, object?>[]? cachedTagsStorage;

/// <summary>
/// Try to get the started <see cref="Activity"/> for the running <see
Expand Down Expand Up @@ -69,29 +51,20 @@ public static bool HasStarted(HttpContextBase context, out Activity? aspNetActiv
/// </summary>
/// <param name="textMapPropagator"><see cref="TextMapPropagator"/>.</param>
/// <param name="context"><see cref="HttpContextBase"/>.</param>
/// <param name="onRequestStartedCallback">Callback action.</param>
/// <param name="onRequestStartedCallback">Function creating activity.</param>
/// <returns>New root activity.</returns>
public static Activity? StartAspNetActivity(TextMapPropagator textMapPropagator, HttpContextBase context, Action<Activity?, HttpContextBase>? onRequestStartedCallback)
public static Activity? StartAspNetActivity(TextMapPropagator textMapPropagator, HttpContextBase context, Func<HttpContextBase, ActivityContext, Activity?>? onRequestStartedCallback)
{
var propagationContext = textMapPropagator.Extract(default, context.Request, HttpRequestHeaderValuesGetter);

KeyValuePair<string, object?>[]? tags;
if (context.Request?.Unvalidated?.Path is string path)
{
tags = cachedTagsStorage ??= new KeyValuePair<string, object?>[1];

tags[0] = new KeyValuePair<string, object?>(SemanticConventions.AttributeUrlPath, path);
}
else
Activity? activity = null;
try
{
tags = null;
activity = onRequestStartedCallback?.Invoke(context, propagationContext.ActivityContext);
}

var activity = AspNetSource.StartActivity(AspNetActivityName, ActivityKind.Server, propagationContext.ActivityContext, tags);

if (tags is not null)
catch (Exception callbackEx)
{
tags[0] = default;
AspNetTelemetryEventSource.Log.CallbackException(activity, "Start", callbackEx);
}

if (activity != null)
Expand All @@ -107,20 +80,10 @@ public static bool HasStarted(HttpContextBase context, out Activity? aspNetActiv
context.Items[ContextKey] = new ContextHolder(activity);
}

try
{
onRequestStartedCallback?.Invoke(activity, context);
}
catch (Exception callbackEx)
{
AspNetTelemetryEventSource.Log.CallbackException(activity, "OnStarted", callbackEx);
}

AspNetTelemetryEventSource.Log.ActivityStarted(activity);
}
else
{
onRequestStartedCallback?.Invoke(activity, context);
context.Items[ContextKey] = StartedButNotSampledObj;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
* Updated OpenTelemetry core component version(s) to `1.13.0`.
([#3158](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3158))

* **Breaking Change**: This module is no longer responsible for creating activities.
The contract of `TelemetryHttpModuleOptions.OnRequestStartedCallback` was changed
to `Func<HttpContextBase, ActivityContext, Activity?>?`. The consumer is now
responsible for providing function returning `Activity`.
([#3151](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3151))

## 1.12.0-beta.2

Released 2025-Sep-18
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<Compile Include="$(RepoRoot)\src\Shared\AssemblyVersionExtensions.cs" Link="Includes\AssemblyVersionExtensions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\ExceptionExtensions.cs" Link="Includes\ExceptionExtensions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
<Compile Include="$(RepoRoot)\src\Shared\RequestDataHelper.cs" Link="Includes\RequestDataHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\SemanticConventions.cs" Link="Includes\SemanticConventions.cs" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ public TextMapPropagator TextMapPropagator
}

/// <summary>
/// Gets or sets a callback action to be fired when a request is started.
/// Gets or sets a callback function to be fired when a request is started.
/// This function should return the <see cref="Activity"/> created to represent the request.
/// </summary>
public Action<Activity?, HttpContextBase>? OnRequestStartedCallback { get; set; }
public Func<HttpContextBase, ActivityContext, Activity?>? OnRequestStartedCallback { get; set; }

/// <summary>
/// Gets or sets a callback action to be fired when a request is stopped.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Reflection;
using OpenTelemetry.Instrumentation.AspNet.Implementation;
Expand All @@ -18,7 +19,9 @@ internal sealed class AspNetInstrumentation : IDisposable
public static readonly Assembly Assembly = typeof(HttpInListener).Assembly;
public static readonly AssemblyName AssemblyName = Assembly.GetName();
public static readonly string MeterName = AssemblyName.Name!;
public static readonly string ActivitySourceName = AssemblyName.Name;
public static readonly Meter Meter = new(MeterName, Assembly.GetPackageVersion());
public static readonly ActivitySource ActivitySource = new(ActivitySourceName, Assembly.GetPackageVersion());
public static readonly Histogram<double> HttpServerDuration = Meter.CreateHistogram(
"http.server.request.duration",
unit: "s",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public static TracerProviderBuilder AddAspNetInstrumentation(
{
return AspNetInstrumentation.Instance.HandleManager.AddTracingHandle();
});
tracerProviderBuilder.AddSource("OpenTelemetry.Instrumentation.AspNet");
tracerProviderBuilder.AddSource(AspNetInstrumentation.ActivitySourceName);
});
});
}
Expand Down
10 changes: 10 additions & 0 deletions src/OpenTelemetry.Instrumentation.AspNet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
* Updated OpenTelemetry core component version(s) to `1.13.0`.
([#3158](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3158))

* Following attributes are available while sampling:
* `http.request.method`,
* `server.address`,
* `server.port`,
* `url.path`,
* `url.query`,
* `url.scheme`,
* `user_agent.original`.
([#3151](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3151))

## 1.12.0-beta.2

Released 2025-Sep-18
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ public HttpInListener()
{
TelemetryHttpModule.Options.TextMapPropagator = Propagators.DefaultTextMapPropagator;

TelemetryHttpModule.Options.OnRequestStartedCallback += this.OnStartActivity;
TelemetryHttpModule.Options.OnRequestStartedCallback += this.StartActivity;
TelemetryHttpModule.Options.OnRequestStoppedCallback += this.OnStopActivity;
TelemetryHttpModule.Options.OnExceptionCallback += this.OnException;
}

public void Dispose()
{
TelemetryHttpModule.Options.OnRequestStartedCallback -= this.OnStartActivity;
TelemetryHttpModule.Options.OnRequestStartedCallback -= this.StartActivity;
TelemetryHttpModule.Options.OnRequestStoppedCallback -= this.OnStopActivity;
TelemetryHttpModule.Options.OnExceptionCallback -= this.OnException;
}
Expand Down Expand Up @@ -111,7 +111,7 @@ private void RecordDuration(Activity? activity, HttpContextBase context, Excepti
AspNetInstrumentation.HttpServerDuration.Record(duration, tags);
}

private void OnStartActivity(Activity? activity, HttpContextBase context)
private Activity? StartActivity(HttpContextBase context, ActivityContext activityContext)
{
if (AspNetInstrumentation.Instance.HandleManager.TracingHandles == 0)
{
Expand All @@ -122,16 +122,47 @@ private void OnStartActivity(Activity? activity, HttpContextBase context)
this.beginTimestamp.Value = Stopwatch.GetTimestamp();
}

return;
return null;
}

if (activity == null)
TagList tags = default;

var request = context.Request;
var originalHttpMethod = request.HttpMethod;
var activityName = this.requestDataHelper.GetActivityDisplayName(originalHttpMethod);
this.requestDataHelper.SetHttpMethodTag(ref tags, originalHttpMethod);

var url = request.Url;
tags.Add(SemanticConventions.AttributeServerAddress, url.Host);
tags.Add(SemanticConventions.AttributeServerPort, url.Port);
tags.Add(SemanticConventions.AttributeUrlScheme, url.Scheme);

if (context.Request.Unvalidated?.Path is string path)
{
AspNetInstrumentationEventSource.Log.NullActivity(nameof(this.OnStartActivity));
return;
tags.Add(SemanticConventions.AttributeUrlPath, path);
}

var userAgent = request.UserAgent;
if (!string.IsNullOrEmpty(userAgent))
{
tags.Add(SemanticConventions.AttributeUserAgentOriginal, userAgent);
}

var query = url.Query;
var options = AspNetInstrumentation.Instance.TraceOptions;
if (!string.IsNullOrEmpty(query))
{
var queryString = query.StartsWith("?", StringComparison.Ordinal) ? query.Substring(1) : query;
tags.Add(SemanticConventions.AttributeUrlQuery, options.DisableUrlQueryRedaction ? queryString : RedactionHelper.GetRedactedQueryString(queryString));
}

var activity = AspNetInstrumentation.ActivitySource.StartActivity(activityName, ActivityKind.Server, activityContext, tags);

if (activity == null)
{
AspNetInstrumentationEventSource.Log.NullActivity(nameof(this.StartActivity));
return null;
}

if (activity.IsAllDataRequested)
{
Expand All @@ -148,49 +179,23 @@ private void OnStartActivity(Activity? activity, HttpContextBase context)
AspNetInstrumentationEventSource.Log.RequestIsFilteredOut(activity.OperationName);
activity.IsAllDataRequested = false;
activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded;
return;
return activity;
}
}
catch (Exception ex)
{
AspNetInstrumentationEventSource.Log.RequestFilterException(activity.OperationName, ex);
activity.IsAllDataRequested = false;
activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded;
return;
return activity;
}

var request = context.Request;

// see the spec https://github.com/open-telemetry/semantic-conventions/blob/v1.24.0/docs/http/http-spans.md
var originalHttpMethod = request.HttpMethod;
this.requestDataHelper.SetActivityDisplayName(activity, originalHttpMethod);

var url = request.Url;
activity.SetTag(SemanticConventions.AttributeServerAddress, url.Host);
activity.SetTag(SemanticConventions.AttributeServerPort, url.Port);
activity.SetTag(SemanticConventions.AttributeUrlScheme, url.Scheme);

this.requestDataHelper.SetHttpMethodTag(activity, originalHttpMethod);

var protocolVersion = RequestDataHelperExtensions.GetHttpProtocolVersion(request);
if (!string.IsNullOrEmpty(protocolVersion))
{
activity.SetTag(SemanticConventions.AttributeNetworkProtocolVersion, protocolVersion);
}

var query = url.Query;
if (!string.IsNullOrEmpty(query))
{
var queryString = query.StartsWith("?", StringComparison.Ordinal) ? query.Substring(1) : query;
activity.SetTag(SemanticConventions.AttributeUrlQuery, options.DisableUrlQueryRedaction ? queryString : RedactionHelper.GetRedactedQueryString(queryString));
}

var userAgent = request.UserAgent;
if (!string.IsNullOrEmpty(userAgent))
{
activity.SetTag(SemanticConventions.AttributeUserAgentOriginal, userAgent);
}

try
{
options.EnrichWithHttpRequest?.Invoke(activity, request);
Expand All @@ -200,6 +205,8 @@ private void OnStartActivity(Activity? activity, HttpContextBase context)
AspNetInstrumentationEventSource.Log.EnrichmentException("OnStartActivity", ex);
}
}

return activity;
}

private void OnStopActivity(Activity? activity, HttpContextBase context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public static TagList GetTagListFromConnectionInfo(string? dataSource, string? d
? MicrosoftSqlServerDbSystemName
: MicrosoftSqlServerDbSystem;

var tags = new TagList { };
TagList tags = default;

if (options.EmitOldAttributes)
{
Expand Down
5 changes: 5 additions & 0 deletions src/OpenTelemetry.Instrumentation.Wcf/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
* Updated OpenTelemetry core component version(s) to `1.13.0`.
([#3158](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3158))

* **Breaking changes** Adjust to breaking changes from
`OpenTelemetry.Instrumentation.AspNet` version `1.12.0-beta.3`.
Fixing span hierarchy when hosted in ASP.NET.
([#3151](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3151))

## 1.12.0-beta.1

Released 2025-May-06
Expand Down
Loading
Loading