diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs index f772b32da8..7bcc55630c 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs @@ -187,6 +187,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http } catch (Exception ex) { + Log.ApplicationError(ex); error = ex; } finally diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/IKestrelTrace.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/IKestrelTrace.cs index 4da5b805f0..2b31bfefd4 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/IKestrelTrace.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/IKestrelTrace.cs @@ -1,3 +1,4 @@ +using System; using Microsoft.Extensions.Logging; namespace Microsoft.AspNet.Server.Kestrel.Infrastructure @@ -27,5 +28,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure void ConnectionWrite(long connectionId, int count); void ConnectionWriteCallback(long connectionId, int status); + + void ApplicationError(Exception ex); } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/KestrelTrace.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/KestrelTrace.cs index df4a3a9ac1..e55ad72846 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/KestrelTrace.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/KestrelTrace.cs @@ -82,6 +82,11 @@ namespace Microsoft.AspNet.Server.Kestrel // Reserved: Event ID 12 } + public virtual void ApplicationError(Exception ex) + { + _logger.LogError(13, "An unhandled exception was thrown by the application.", ex); + } + public virtual void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func formatter) { _logger.Log(logLevel, eventId, state, exception, formatter); diff --git a/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs b/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs index 4a74eb84dd..b426214341 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs @@ -7,13 +7,13 @@ using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Kestrel; using Microsoft.AspNet.Server.Kestrel.Filter; -using Microsoft.AspNet.Server.Kestrel.Http; using Microsoft.Dnx.Runtime; using Microsoft.Dnx.Runtime.Infrastructure; +using Microsoft.Extensions.Logging; using Xunit; -using Microsoft.AspNet.Http.Features; namespace Microsoft.AspNet.Server.KestrelTests { @@ -552,6 +552,9 @@ namespace Microsoft.AspNet.Server.KestrelTests { bool onStartingCalled = false; + var testLogger = new TestApplicationErrorLogger(); + testContext.Log = new KestrelTrace(testLogger); + using (var server = new TestServer(frame => { var response = frame.Get(); @@ -595,6 +598,7 @@ namespace Microsoft.AspNet.Server.KestrelTests ""); Assert.False(onStartingCalled); + Assert.Equal(2, testLogger.ApplicationErrorsLogged); } } } @@ -605,6 +609,9 @@ namespace Microsoft.AspNet.Server.KestrelTests { bool onStartingCalled = false; + var testLogger = new TestApplicationErrorLogger(); + testContext.Log = new KestrelTrace(testLogger); + using (var server = new TestServer(async frame => { var response = frame.Get(); @@ -633,6 +640,7 @@ namespace Microsoft.AspNet.Server.KestrelTests "Hello World"); Assert.True(onStartingCalled); + Assert.Equal(1, testLogger.ApplicationErrorsLogged); } } } @@ -643,6 +651,9 @@ namespace Microsoft.AspNet.Server.KestrelTests { bool onStartingCalled = false; + var testLogger = new TestApplicationErrorLogger(); + testContext.Log = new KestrelTrace(testLogger); + using (var server = new TestServer(async frame => { var response = frame.Get(); @@ -671,6 +682,7 @@ namespace Microsoft.AspNet.Server.KestrelTests "Hello"); Assert.True(onStartingCalled); + Assert.Equal(1, testLogger.ApplicationErrorsLogged); } } } @@ -834,5 +846,29 @@ namespace Microsoft.AspNet.Server.KestrelTests } } } + + private class TestApplicationErrorLogger : ILogger + { + public int ApplicationErrorsLogged { get; set; } + + public IDisposable BeginScopeImpl(object state) + { + throw new NotImplementedException(); + } + + public bool IsEnabled(LogLevel logLevel) + { + throw new NotImplementedException(); + } + + public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func formatter) + { + // Application errors are logged using 13 as the eventId. + if (eventId == 13) + { + ApplicationErrorsLogged++; + } + } + } } }