Adding telemetry publish for unhandled exceptions to developer exception page and exception handler #180
This commit is contained in:
parent
3657a1a14b
commit
7b9cfac65a
|
|
@ -5,6 +5,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
|
@ -29,6 +30,7 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
private static readonly bool IsMono = Type.GetType("Mono.Runtime") != null;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFileProvider _fileProvider;
|
||||
private readonly TelemetrySource _telemetrySource;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DeveloperExceptionPageMiddleware"/> class
|
||||
|
|
@ -39,7 +41,8 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
RequestDelegate next,
|
||||
ErrorPageOptions options,
|
||||
ILoggerFactory loggerFactory,
|
||||
IApplicationEnvironment appEnvironment)
|
||||
IApplicationEnvironment appEnvironment,
|
||||
TelemetrySource telemetrySource)
|
||||
{
|
||||
if (next == null)
|
||||
{
|
||||
|
|
@ -55,6 +58,7 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
_options = options;
|
||||
_logger = loggerFactory.CreateLogger<DeveloperExceptionPageMiddleware>();
|
||||
_fileProvider = options.FileProvider ?? new PhysicalFileProvider(appEnvironment.ApplicationBasePath);
|
||||
_telemetrySource = telemetrySource;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -72,6 +76,7 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("An unhandled exception has occurred while executing the request", ex);
|
||||
|
||||
if (context.Response.HasStarted)
|
||||
{
|
||||
_logger.LogWarning("The response has already started, the error page middleware will not be executed.");
|
||||
|
|
@ -84,6 +89,9 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
context.Response.StatusCode = 500;
|
||||
|
||||
await DisplayException(context, ex);
|
||||
|
||||
_telemetrySource.WriteTelemetry("Microsoft.AspNet.Diagnostics.UnhandledException", new { httpContext = context, exception = ex });
|
||||
|
||||
return;
|
||||
}
|
||||
catch (Exception ex2)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
|
@ -17,8 +18,13 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
private readonly ExceptionHandlerOptions _options;
|
||||
private readonly ILogger _logger;
|
||||
private readonly Func<object, Task> _clearCacheHeadersDelegate;
|
||||
private readonly TelemetrySource _telemetrySource;
|
||||
|
||||
public ExceptionHandlerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, ExceptionHandlerOptions options)
|
||||
public ExceptionHandlerMiddleware(
|
||||
RequestDelegate next,
|
||||
ILoggerFactory loggerFactory,
|
||||
ExceptionHandlerOptions options,
|
||||
TelemetrySource telemetrySource)
|
||||
{
|
||||
_next = next;
|
||||
_options = options;
|
||||
|
|
@ -28,6 +34,7 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
_options.ExceptionHandler = _next;
|
||||
}
|
||||
_clearCacheHeadersDelegate = ClearCacheHeaders;
|
||||
_telemetrySource = telemetrySource;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
|
|
@ -63,6 +70,9 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
context.Response.OnStarting(_clearCacheHeadersDelegate, context.Response);
|
||||
|
||||
await _options.ExceptionHandler(context);
|
||||
|
||||
_telemetrySource.WriteTelemetry("Microsoft.AspNet.Diagnostics.HandledException", new { httpContext = context, exception = ex });
|
||||
|
||||
// TODO: Optional re-throw? We'll re-throw the original exception by default if the error handler throws.
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,15 @@
|
|||
"Microsoft.Extensions.Logging.Abstractions": "1.0.0-*",
|
||||
"Microsoft.Extensions.OptionsModel": "1.0.0-*",
|
||||
"Microsoft.Dnx.Compilation.Abstractions": "1.0.0-*",
|
||||
"Microsoft.Extensions.WebEncoders.Core": "1.0.0-*"
|
||||
"Microsoft.Extensions.WebEncoders.Core": "1.0.0-*",
|
||||
"System.Diagnostics.Tracing.Telemetry": "4.0.0-beta-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnx451": {},
|
||||
"dnx451": {
|
||||
"frameworkAssemblies": {
|
||||
"System.Runtime": ""
|
||||
}
|
||||
},
|
||||
"dnxcore50": {
|
||||
"dependencies": {
|
||||
"System.Reflection.Extensions": "4.0.1-beta-*"
|
||||
|
|
|
|||
|
|
@ -3,16 +3,20 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Diagnostics.Views;
|
||||
using Microsoft.AspNet.FileProviders;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Dnx.Runtime;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Xunit;
|
||||
|
|
@ -298,7 +302,8 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
(httpContext) => { return Task.FromResult(0); },
|
||||
errorPageOptions,
|
||||
new LoggerFactory(),
|
||||
new TestApplicationEnvironment());
|
||||
new TestApplicationEnvironment(),
|
||||
new TelemetryListener("Microsoft.Aspnet"));
|
||||
|
||||
return middleware;
|
||||
}
|
||||
|
|
@ -471,5 +476,35 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
public IEnumerable<string> ExpectedErrorCode { get; set; }
|
||||
public IEnumerable<string> ExpectedPostErrorCode { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UnhandledErrorsWriteToDiagnosticTelemetryWhenUsingExceptionPage()
|
||||
{
|
||||
// Arrange
|
||||
TelemetryListener telemetryListener = null;
|
||||
var server = TestServer.Create(app =>
|
||||
{
|
||||
telemetryListener = app.ApplicationServices.GetRequiredService<TelemetryListener>();
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.Run(context =>
|
||||
{
|
||||
throw new Exception("Test exception");
|
||||
});
|
||||
});
|
||||
var listener = new TestTelemetryListener();
|
||||
telemetryListener.SubscribeWithAdapter(listener);
|
||||
|
||||
// Act
|
||||
await server.CreateClient().GetAsync("/path");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(listener.EndRequest?.HttpContext);
|
||||
Assert.Null(listener.HostingUnhandledException?.HttpContext);
|
||||
Assert.Null(listener.HostingUnhandledException?.Exception);
|
||||
Assert.NotNull(listener.DiagnosticUnhandledException?.HttpContext);
|
||||
Assert.NotNull(listener.DiagnosticUnhandledException?.Exception);
|
||||
Assert.Null(listener.DiagnosticHandledException?.HttpContext);
|
||||
Assert.Null(listener.DiagnosticHandledException?.Exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
|
@ -10,6 +11,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics
|
||||
|
|
@ -321,5 +323,45 @@ namespace Microsoft.AspNet.Diagnostics
|
|||
Assert.Equal("abcdef", values.First());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandledErrorsWriteToDiagnosticTelemetryWhenUsingExceptionHandler()
|
||||
{
|
||||
// Arrange
|
||||
TelemetryListener telemetryListener = null;
|
||||
|
||||
var server = TestServer.Create(app =>
|
||||
{
|
||||
telemetryListener = app.ApplicationServices.GetRequiredService<TelemetryListener>();
|
||||
|
||||
app.UseExceptionHandler("/handle-errors");
|
||||
app.Map("/handle-errors", (innerAppBuilder) =>
|
||||
{
|
||||
innerAppBuilder.Run(async (httpContext) =>
|
||||
{
|
||||
await httpContext.Response.WriteAsync("Handled error in a custom way.");
|
||||
});
|
||||
});
|
||||
app.Run(context =>
|
||||
{
|
||||
throw new Exception("Test exception");
|
||||
});
|
||||
});
|
||||
|
||||
var listener = new TestTelemetryListener();
|
||||
telemetryListener.SubscribeWithAdapter(listener);
|
||||
|
||||
// Act
|
||||
await server.CreateClient().GetAsync(string.Empty);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(listener.EndRequest?.HttpContext);
|
||||
Assert.Null(listener.HostingUnhandledException?.HttpContext);
|
||||
Assert.Null(listener.HostingUnhandledException?.Exception);
|
||||
Assert.Null(listener.DiagnosticUnhandledException?.HttpContext);
|
||||
Assert.Null(listener.DiagnosticUnhandledException?.Exception);
|
||||
Assert.NotNull(listener.DiagnosticHandledException?.HttpContext);
|
||||
Assert.NotNull(listener.DiagnosticHandledException?.Exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Extensions.TelemetryAdapter;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics
|
||||
{
|
||||
public class TestTelemetryListener
|
||||
{
|
||||
public class OnRequestEventData
|
||||
{
|
||||
public IProxyHttpContext HttpContext { get; set; }
|
||||
}
|
||||
|
||||
public class OnExceptionEventData
|
||||
{
|
||||
public IProxyHttpContext HttpContext { get; set; }
|
||||
public IProxyException Exception { get; set; }
|
||||
}
|
||||
|
||||
public OnRequestEventData BeginRequest { get; set; }
|
||||
public OnRequestEventData EndRequest { get; set; }
|
||||
public OnExceptionEventData HostingUnhandledException { get; set; }
|
||||
public OnExceptionEventData DiagnosticUnhandledException { get; set; }
|
||||
public OnExceptionEventData DiagnosticHandledException { get; set; }
|
||||
|
||||
[TelemetryName("Microsoft.AspNet.Hosting.BeginRequest")]
|
||||
public virtual void OnBeginRequest(IProxyHttpContext httpContext)
|
||||
{
|
||||
BeginRequest = new OnRequestEventData()
|
||||
{
|
||||
HttpContext = httpContext
|
||||
};
|
||||
}
|
||||
|
||||
[TelemetryName("Microsoft.AspNet.Hosting.EndRequest")]
|
||||
public virtual void OnEndRequest(IProxyHttpContext httpContext)
|
||||
{
|
||||
EndRequest = new OnRequestEventData()
|
||||
{
|
||||
HttpContext = httpContext
|
||||
};
|
||||
}
|
||||
|
||||
[TelemetryName("Microsoft.AspNet.Hosting.UnhandledException")]
|
||||
public virtual void OnHostingUnhandledException(IProxyHttpContext httpContext, IProxyException exception)
|
||||
{
|
||||
HostingUnhandledException = new OnExceptionEventData()
|
||||
{
|
||||
HttpContext = httpContext,
|
||||
Exception = exception
|
||||
};
|
||||
}
|
||||
|
||||
[TelemetryName("Microsoft.AspNet.Diagnostics.UnhandledException")]
|
||||
public virtual void OnDiagnosticUnhandledException(IProxyHttpContext httpContext, IProxyException exception)
|
||||
{
|
||||
DiagnosticUnhandledException = new OnExceptionEventData()
|
||||
{
|
||||
HttpContext = httpContext,
|
||||
Exception = exception
|
||||
};
|
||||
}
|
||||
|
||||
[TelemetryName("Microsoft.AspNet.Diagnostics.HandledException")]
|
||||
public virtual void OnDiagnosticHandledException(IProxyHttpContext httpContext, IProxyException exception)
|
||||
{
|
||||
DiagnosticHandledException = new OnExceptionEventData()
|
||||
{
|
||||
HttpContext = httpContext,
|
||||
Exception = exception
|
||||
};
|
||||
}
|
||||
|
||||
public interface IProxyHttpContext
|
||||
{
|
||||
}
|
||||
|
||||
public interface IProxyException
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
"Microsoft.AspNet.TestHost": "1.0.0-*",
|
||||
"Microsoft.AspNet.Testing": "1.0.0-*",
|
||||
"Microsoft.Extensions.DependencyInjection": "1.0.0-*",
|
||||
"Microsoft.Extensions.TelemetryAdapter": "1.0.0-*",
|
||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue