Reputation: 4629
When implementing my own Exception handler using app.UseExceptionHandler
with an exception handler lambda / delegate (Documentation) I do not want Microsofts Exception handler middleware to log this error:
An unhandled exception has occurred while executing the request.
This exception message clutters my log file because I take care of logging the exception with an appropriate LogLevel by myself.
This is how I register my own ErrorHandler:
app.UseExceptionHandler(errorApp =>
errorApp.Run(ErrorHandler));
As described in this issue filtering this exact message and nothing else is not possible in a simple way.
How do I filter this exact log message and nothing else from the middleware?
I am using:
Upvotes: 10
Views: 4396
Reputation: 560
I think I found much simpler solution:
"Serilog": {
"MinimumLevel": {
...
"Override": {
...
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "Fatal"
}
}
Trick is that ExceptionHandlerMiddleware
logs with lover level=Error, but level=Fatal is above.
Upvotes: 0
Reputation: 2015
I have replaced app.UseExceptionHandler with a custom middleware in my program, it works like a charm.
Startup.cs:
app.UseMiddleware<HttpExceptionMiddleware>();
HttpExceptionMiddleware.cs
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
internal class HttpExceptionMiddleware
{
private readonly RequestDelegate next;
public HttpExceptionMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await this.next.Invoke(context);
}
catch (HttpException e)
{
var response = context.Response;
if (response.HasStarted)
{
throw;
}
response.StatusCode = (int) e.StatusCode;
response.ContentType = "application/json; charset=utf-8";
response.Headers[HeaderNames.CacheControl] = "no-cache";
response.Headers[HeaderNames.Pragma] = "no-cache";
response.Headers[HeaderNames.Expires] = "-1";
response.Headers.Remove(HeaderNames.ETag);
var bodyObj = new {
Message = e.Message,
Status = e.StatusCode.ToString()
};
var body = JsonSerializer.Serialize(bodyObj);
await context.Response.WriteAsync(body);
}
}
}
HTTPException.cs
using System;
using System.Net;
public class HttpException : Exception
{
public HttpStatusCode StatusCode { get; }
public HttpException(HttpStatusCode statusCode)
{
this.StatusCode = statusCode;
}
public HttpException(int httpStatusCode)
: this((HttpStatusCode) httpStatusCode)
{
}
public HttpException(HttpStatusCode statusCode, string message)
: base(message)
{
this.StatusCode = statusCode;
}
public HttpException(int httpStatusCode, string message)
: this((HttpStatusCode) httpStatusCode, message)
{
}
public HttpException(HttpStatusCode statusCode, string message, Exception inner)
: base(message, inner)
{
}
public HttpException(int httpStatusCode, string message, Exception inner)
: this((HttpStatusCode) httpStatusCode, message, inner)
{
}
}
Upvotes: 1
Reputation: 4629
As described in the issue mentioned above, we can use a Filter expression for this. Unfortunately the issue only describes a solution for a deprecated package and is filtering all messages from the Middleware, not only the mentioned message.
appsettings.json
with this configuration: "Serilog": {
"Using": [ "Serilog.Expressions" ],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "@l='Error' and SourceContext='Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware' and @mt='An unhandled exception has occurred while executing the request.'"
}
}
]
}
appsettings.json
as documented, e.g.:Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
This way you can keep all other messages from the ExceptionHandlerMiddleware
and just disable the redundant error log message.
Side note: In case the response already has started, our custom exception handler will not be executed - but a warning will be logged and the exception will be rethrown and later logged by another application layer - at least in the application I tested. You can test this behavior by adding this code somewhere before the exception is thrown (context
is the current HttpContext):
await context.Response.WriteAsync("fish");
Upvotes: 4