How to link exceptions to requests in Application Insights on Azure?

What I ended-up doing:

using AppFunc = Func<IDictionary<string, object>, Task>;
public class InsightsReportMiddleware
{
    readonly AppFunc next;
    readonly TelemetryClient telemetryClient;

    public InsightsReportMiddleware(AppFunc next, TelemetryClient telemetryClient)
    {
        if (next == null)
        {
            throw new ArgumentNullException("next");
        }

        this.telemetryClient = telemetryClient;
        this.next = next;
    }

    public async Task Invoke(IDictionary<string, object> environment)
    {
        var ctx = new OwinContext(environment);
        var rt = new RequestTelemetry()
        {
            Url = ctx.Request.Uri,
            HttpMethod = ctx.Request.Method,
            Name = ctx.Request.Path.ToString(),
            Timestamp = DateTimeOffset.Now
        };
        environment.Add("requestTelemetry", rt);

        var sw = new Stopwatch();
        sw.Start();
        await next(environment);
        sw.Stop();

        rt.ResponseCode = ctx.Response.StatusCode.ToString();
        rt.Success = ctx.Response.StatusCode < 400;
        rt.Duration = sw.Elapsed;
        telemetryClient.TrackRequest(rt);
    }
}

public class InsightsExceptionLogger : ExceptionLogger
{
    readonly TelemetryClient telemetryClient;

    public InsightsExceptionLogger(TelemetryClient telemetryClient)
    {
        this.telemetryClient = telemetryClient;            
    }

    public override Task LogAsync(ExceptionLoggerContext context, System.Threading.CancellationToken cancellationToken)
    {
        var owinContext = context.Request.GetOwinEnvironment();
        ExceptionTelemetry exceptionTelemetry = null;
        if (owinContext != null)
        {
            object obj;
            if (owinContext.TryGetValue("requestTelemetry", out obj))
            {
                var requestTelemetry = obj as RequestTelemetry;
                exceptionTelemetry = new ExceptionTelemetry(context.Exception)
                {
                    Timestamp = DateTimeOffset.Now
                };
                exceptionTelemetry.Context.Operation.Id = requestTelemetry.Id;
            }
        }

        if (exceptionTelemetry != null)
        {
            telemetryClient.TrackException(exceptionTelemetry);
        }
        else
        {
            telemetryClient.TrackException(context.Exception);                
        }

        return Task.FromResult<object>(null);
    }

    public override void Log(ExceptionLoggerContext context)
    {
        telemetryClient.TrackException(context.Exception);
    }
}

Application Insights links exceptions and requests by comparing ExceptionTelemetry.Context.Operation.Id and RequestTelemetry.Id.

I don't have a code sample for OWIN, however the ASP.NET 5 package of the Application Insights SDK has similar middleware components for tracking exceptions and requests. I hope you can use this information to build a solution for OWIN.

We create a RequestTelemetry instance and store it in the request processing environment before invoking the next middleware component which performs actual request processing. In ASP.NET 5, we register RequestTelemetry as a request-scoped service. With OWIN, I'd imagine your middleware component would create it and store it in the environment dictionary.

We also have an ITelemetryInitializer, called OperationIdTelemetryInitializer, that sets the ITelemetry.Context.Operation.Id with the RequestTelemetry.Id extracted from the environment. This initializer needs to be added to the TelemetryConfiguration used to create the TelemetryClient instances in your application. TelemetryConfiguration.Active is used by default.


There is an overload of TelemetryClient.TrackException method that accepts dictionary of properties. It is designed specifically to clasify and search for the exception. This allows to generate an error Id, and link the error to AppInsights.

An example of error handling:

var errorId = GenerateErrorId();

var trackProperties = new Dictionary<string, string>();
trackProperties.Add("ErrorId", errorId);

var ai = new TelemetryClient();
ai.TrackException(exception, trackProperties);

JObject resp = new JObject();
resp["message"] = exception.Message + " - " + errorId;

await context.Response.WriteAsync(resp.ToString());

For my current client, we're not yet OWIN-ed up.

I registered a DelegatingHandler with WebAPI that sticks the current request into the thread's SynchronizationContext via CallContext.LogicalSetData and removes it after the request is complete.

In my existing logging system, which had to be retro-fitted with the Application Insights stuff, I then grab the request from the thread via CallContext.LogicalSetData and set about getting the HttpContext which is placed into the request properties by the framework, then from the HttpContext.Items, I get the RequestTelemetry instance.

Ultimately, this is all needed because I can't get access to the request or action or anything from the IoC container that's newing-up the services.

Eventually we might rewrite some of this to allow improved creation and flowing of an OperationContext or InstrumentationContext style object down the stack and get rid of the handler and CallContext funny business.