Skip to content

Commit

Permalink
New design for TelemetryHttpModule using ActivitySource + OpenTelemet…
Browse files Browse the repository at this point in the history
…ry.API. (#2249)
  • Loading branch information
CodeBlanch authored Aug 12, 2021
1 parent c9c7869 commit dfc8e6d
Show file tree
Hide file tree
Showing 13 changed files with 165 additions and 947 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
OpenTelemetry.Instrumentation.AspNet.ActivityExtensions
const OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.AspNetActivityName = "Microsoft.AspNet.HttpReqIn" -> string
const OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.AspNetSourceName = "OpenTelemetry.Instrumentation.AspNet.Telemetry" -> string
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.Dispose() -> void
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.Init(System.Web.HttpApplication context) -> void
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.ParseHeaders.get -> bool
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.ParseHeaders.set -> void
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.OnExceptionCallback.get -> System.Action<System.Diagnostics.Activity, System.Exception>
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.OnExceptionCallback.set -> void
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.OnRequestStartedCallback.get -> System.Action<System.Diagnostics.Activity, System.Web.HttpContext>
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.OnRequestStartedCallback.set -> void
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.OnRequestStoppedCallback.get -> System.Action<System.Diagnostics.Activity, System.Web.HttpContext>
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.OnRequestStoppedCallback.set -> void
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.TelemetryHttpModule() -> void
static OpenTelemetry.Instrumentation.AspNet.ActivityExtensions.Extract(this System.Diagnostics.Activity activity, System.Collections.Specialized.NameValueCollection requestHeaders) -> bool
static OpenTelemetry.Instrumentation.AspNet.ActivityExtensions.TryParse(this System.Diagnostics.Activity activity, System.Collections.Specialized.NameValueCollection requestHeaders) -> bool
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.TextMapPropagator.get -> OpenTelemetry.Context.Propagation.TraceContextPropagator
OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.TextMapPropagator.set -> void

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Web;
using OpenTelemetry.Context.Propagation;

namespace OpenTelemetry.Instrumentation.AspNet
{
Expand All @@ -27,97 +29,105 @@ namespace OpenTelemetry.Instrumentation.AspNet
internal static class ActivityHelper
{
/// <summary>
/// Listener name.
/// Key to store the activity in HttpContext.
/// </summary>
public const string AspNetListenerName = "OpenTelemetry.Instrumentation.AspNet.Telemetry";
public const string ActivityKey = "__AspnetActivity__";

/// <summary>
/// Activity name for http request.
/// </summary>
public const string AspNetActivityName = "Microsoft.AspNet.HttpReqIn";
private static readonly ActivitySource AspNetSource = new ActivitySource(TelemetryHttpModule.AspNetSourceName);
private static readonly Func<HttpRequest, string, IEnumerable<string>> HttpRequestHeaderValuesGetter = (request, name) => request.Headers.GetValues(name);

/// <summary>
/// Event name for the activity start event.
/// Creates root (first level) activity that describes incoming request.
/// </summary>
public const string AspNetActivityStartName = "Microsoft.AspNet.HttpReqIn.Start";
/// <param name="textMapPropagator"><see cref="TextMapPropagator"/>.</param>
/// <param name="context">Current HttpContext.</param>
/// <param name="onRequestStartedCallback">Callback action.</param>
/// <returns>New root activity.</returns>
public static Activity StartAspNetActivity(TextMapPropagator textMapPropagator, HttpContext context, Action<Activity, HttpContext> onRequestStartedCallback)
{
PropagationContext propagationContext = textMapPropagator.Extract(default, context.Request, HttpRequestHeaderValuesGetter);

/// <summary>
/// Key to store the activity in HttpContext.
/// </summary>
public const string ActivityKey = "__AspnetActivity__";
Activity activity = AspNetSource.CreateActivity(TelemetryHttpModule.AspNetActivityName, ActivityKind.Server, propagationContext.ActivityContext);

private static readonly DiagnosticListener AspNetListener = new DiagnosticListener(AspNetListenerName);
if (activity != null)
{
context.Items[ActivityKey] = activity;

private static readonly object EmptyPayload = new object();
if (propagationContext.Baggage != default)
{
Baggage.Current = propagationContext.Baggage;
}

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

AspNetTelemetryEventSource.Log.ActivityStarted(activity);
}

return activity;
}

/// <summary>
/// Stops the activity and notifies listeners about it.
/// </summary>
/// <param name="contextItems">HttpContext.Items.</param>
public static void StopAspNetActivity(IDictionary contextItems)
/// <param name="context">Current HttpContext.</param>
/// <param name="onRequestStoppedCallback">Callback action.</param>
public static void StopAspNetActivity(HttpContext context, Action<Activity, HttpContext> onRequestStoppedCallback)
{
var contextItems = context.Items;
var currentActivity = Activity.Current;
Activity aspNetActivity = (Activity)contextItems[ActivityKey];

if (currentActivity != aspNetActivity)
{
Activity.Current = aspNetActivity;
currentActivity = aspNetActivity;
}

if (currentActivity != null)
if (aspNetActivity != null)
{
// stop Activity with Stop event
AspNetListener.StopActivity(currentActivity, EmptyPayload);
aspNetActivity.Stop();
contextItems[ActivityKey] = null;
}

AspNetTelemetryEventSource.Log.ActivityStopped(currentActivity?.Id, currentActivity?.OperationName);
}

/// <summary>
/// Creates root (first level) activity that describes incoming request.
/// </summary>
/// <param name="context">Current HttpContext.</param>
/// <param name="parseHeaders">Determines if headers should be parsed get correlation ids.</param>
/// <returns>New root activity.</returns>
public static Activity CreateRootActivity(HttpContext context, bool parseHeaders)
{
if (AspNetListener.IsEnabled() && AspNetListener.IsEnabled(AspNetActivityName))
{
var rootActivity = new Activity(AspNetActivityName);

if (parseHeaders)
try
{
rootActivity.Extract(context.Request.Unvalidated.Headers);
onRequestStoppedCallback?.Invoke(aspNetActivity, context);
}

AspNetListener.OnActivityImport(rootActivity, null);

if (StartAspNetActivity(rootActivity))
catch (Exception callbackEx)
{
context.Items[ActivityKey] = rootActivity;
AspNetTelemetryEventSource.Log.ActivityStarted(rootActivity.Id);
return rootActivity;
AspNetTelemetryEventSource.Log.CallbackException(aspNetActivity, "OnStopped", callbackEx);
}

AspNetTelemetryEventSource.Log.ActivityStopped(currentActivity);
}

return null;
if (currentActivity != aspNetActivity)
{
Activity.Current = currentActivity;
}
}

public static void WriteActivityException(IDictionary contextItems, Exception exception)
public static void WriteActivityException(IDictionary contextItems, Exception exception, Action<Activity, Exception> onExceptionCallback)
{
Activity aspNetActivity = (Activity)contextItems[ActivityKey];

if (aspNetActivity != null)
{
if (Activity.Current != aspNetActivity)
try
{
Activity.Current = aspNetActivity;
onExceptionCallback?.Invoke(aspNetActivity, exception);
}
catch (Exception callbackEx)
{
AspNetTelemetryEventSource.Log.CallbackException(aspNetActivity, "OnException", callbackEx);
}

AspNetListener.Write(aspNetActivity.OperationName + ".Exception", exception);
AspNetTelemetryEventSource.Log.ActivityException(aspNetActivity.Id, aspNetActivity.OperationName, exception);
AspNetTelemetryEventSource.Log.ActivityException(aspNetActivity, exception);
}
}

Expand All @@ -136,27 +146,9 @@ internal static void RestoreActivityIfNeeded(IDictionary contextItems)
if (aspNetActivity != null)
{
Activity.Current = aspNetActivity;
AspNetTelemetryEventSource.Log.ActivityRestored(aspNetActivity);
}
}
}

private static bool StartAspNetActivity(Activity activity)
{
if (AspNetListener.IsEnabled(AspNetActivityName, activity, EmptyPayload))
{
if (AspNetListener.IsEnabled(AspNetActivityStartName))
{
AspNetListener.StartActivity(activity, EmptyPayload);
}
else
{
activity.Start();
}

return true;
}

return false;
}
}
}
Loading

0 comments on commit dfc8e6d

Please sign in to comment.