From 5341d20bd203c0f9c3fee362e2ba7a9d9b4d2de8 Mon Sep 17 00:00:00 2001 From: Sebastien Roche Date: Tue, 17 Sep 2019 14:59:07 +0800 Subject: [PATCH 1/5] FEATURE: add ability to customize the LogEventLevel used by the middleware FEATUREL add new dependency injection overloads to offer more flexibility while configuring options --- samples/InlineInitializationSample/Startup.cs | 13 +++++- .../AspNetCore/RequestLoggingMiddleware.cs | 9 ++-- .../RequestLoggingOptions.cs | 34 +++++++++++---- .../SerilogApplicationBuilderExtensions.cs | 41 +++++++++++++++++-- 4 files changed, 81 insertions(+), 16 deletions(-) diff --git a/samples/InlineInitializationSample/Startup.cs b/samples/InlineInitializationSample/Startup.cs index 87d3a0c..1c8b99f 100644 --- a/samples/InlineInitializationSample/Startup.cs +++ b/samples/InlineInitializationSample/Startup.cs @@ -1,10 +1,12 @@ -using Microsoft.AspNetCore.Builder; +using System.Net; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Serilog; +using Serilog.Events; namespace InlineInitializationSample { @@ -46,7 +48,14 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) // Write streamlined request completion events, instead of the more verbose ones from the framework. // To use the default framework request logging instead, remove this line and set the "Microsoft" // level in appsettings.json to "Information". - app.UseSerilogRequestLogging(); + app.UseSerilogRequestLogging(opts => + { + opts.GetLogEventLevel = statusCode => + statusCode == HttpStatusCode.InternalServerError + ? LogEventLevel.Error + : LogEventLevel.Information; + // OR opts.GetLogEventLevel = _ => LogEventLevel.Information; + }); app.UseStaticFiles(); app.UseCookiePolicy(); diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs index db32cbe..886c31a 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs @@ -15,6 +15,7 @@ using System; using System.Diagnostics; using System.Linq; +using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; @@ -29,15 +30,17 @@ class RequestLoggingMiddleware readonly RequestDelegate _next; readonly DiagnosticContext _diagnosticContext; readonly MessageTemplate _messageTemplate; + readonly Func _getLogEventLevel; static readonly LogEventProperty[] NoProperties = new LogEventProperty[0]; - + public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnosticContext, RequestLoggingOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); _next = next ?? throw new ArgumentNullException(nameof(next)); _diagnosticContext = diagnosticContext ?? throw new ArgumentNullException(nameof(diagnosticContext)); + _getLogEventLevel = options.GetLogEventLevel; _messageTemplate = new MessageTemplateParser().Parse(options.MessageTemplate); } @@ -71,8 +74,8 @@ public async Task Invoke(HttpContext httpContext) bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector, int statusCode, double elapsedMs, Exception ex) { var logger = Log.ForContext(); - var level = statusCode > 499 ? LogEventLevel.Error : LogEventLevel.Information; - + var level = _getLogEventLevel((HttpStatusCode)statusCode); + if (!logger.IsEnabled(level)) return false; if (!collector.TryComplete(out var collectedProperties)) diff --git a/src/Serilog.AspNetCore/RequestLoggingOptions.cs b/src/Serilog.AspNetCore/RequestLoggingOptions.cs index f68cf43..949eb36 100644 --- a/src/Serilog.AspNetCore/RequestLoggingOptions.cs +++ b/src/Serilog.AspNetCore/RequestLoggingOptions.cs @@ -12,17 +12,37 @@ // See the License for the specific language governing permissions and // limitations under the License. +using Serilog.Events; using System; +using System.Net; namespace Serilog { - class RequestLoggingOptions + /// + /// Contains options for the Serilog.AspNetCore.RequestLoggingMiddleware. + /// + public class RequestLoggingOptions { - public string MessageTemplate { get; } + /// + /// Gets or sets the message template. The default value is + /// "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms". The + /// template can contain any of the placeholders from the default template, names of properties + /// added by ASP.NET Core, and names of properties added to the . + /// + /// + /// The message template. + /// + public string MessageTemplate { get; set; } - public RequestLoggingOptions(string messageTemplate) - { - MessageTemplate = messageTemplate ?? throw new ArgumentNullException(nameof(messageTemplate)); - } + /// + /// Gets or sets the function returning the LogEventLevel based on the HttpStatusCode. + /// The default behavior returns LogEventLevel.Error when HttpStatusCode is greater than 499 + /// + /// + /// The function returning the LogEventLevel. + /// + public Func GetLogEventLevel { get; set; } + + internal RequestLoggingOptions() { } } -} +} \ No newline at end of file diff --git a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs index 91c7106..237b2e8 100644 --- a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs +++ b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs @@ -13,8 +13,11 @@ // limitations under the License. using System; +using System.Net; using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Options; using Serilog.AspNetCore; +using Serilog.Events; namespace Serilog { @@ -26,6 +29,9 @@ public static class SerilogApplicationBuilderExtensions const string DefaultRequestCompletionMessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms"; + static readonly Func DefaultGetLogEventLevel = + s => (int) s > 499 ? LogEventLevel.Error : LogEventLevel.Information; + /// /// Adds middleware for streamlined request logging. Instead of writing HTTP request information /// like method, path, timing, status code and exception details @@ -43,11 +49,38 @@ public static class SerilogApplicationBuilderExtensions /// The application builder. public static IApplicationBuilder UseSerilogRequestLogging( this IApplicationBuilder app, - string messageTemplate = DefaultRequestCompletionMessageTemplate) + string messageTemplate) + => app.UseSerilogRequestLogging(opts => opts.MessageTemplate = messageTemplate); + + /// + /// Adds middleware for streamlined request logging. Instead of writing HTTP request information + /// like method, path, timing, status code and exception details + /// in several events, this middleware collects information during the request (including from + /// ), and writes a single event at request completion. Add this + /// in Startup.cs before any handlers whose activities should be logged. + /// + /// The application builder. + /// An System.Action`1 to configure the provided . + /// The application builder. + public static IApplicationBuilder UseSerilogRequestLogging( + this IApplicationBuilder app, + Action configureOptions = null) { if (app == null) throw new ArgumentNullException(nameof(app)); - if (messageTemplate == null) throw new ArgumentNullException(nameof(messageTemplate)); - return app.UseMiddleware(new RequestLoggingOptions(messageTemplate)); + + var opts = new RequestLoggingOptions + { + GetLogEventLevel = DefaultGetLogEventLevel, + MessageTemplate = DefaultRequestCompletionMessageTemplate + }; + configureOptions?.Invoke(opts); + + if (opts.MessageTemplate == null) + throw new ArgumentException($"{nameof(opts.MessageTemplate)} cannot be null."); + if (opts.GetLogEventLevel == null) + throw new ArgumentException($"{nameof(opts.GetLogEventLevel)} cannot be null."); + + return app.UseMiddleware(opts); } } -} +} \ No newline at end of file From f35e12ea9e68f0c47743550c4ae8f6dae94a3f6b Mon Sep 17 00:00:00 2001 From: Sebastien Roche Date: Tue, 17 Sep 2019 16:18:55 +0800 Subject: [PATCH 2/5] FEATURE: update sdk version to target latest stable .net core SDK FEATURE: use default empty overload in sample FEATURE: rename GetLogEventLevel to GetLogLevel --- global.json | 4 +-- samples/InlineInitializationSample/Startup.cs | 9 +------ .../AspNetCore/RequestLoggingMiddleware.cs | 26 +++++++++---------- .../{ => AspNetCore}/RequestLoggingOptions.cs | 12 ++++----- .../SerilogApplicationBuilderExtensions.cs | 13 +++++----- 5 files changed, 28 insertions(+), 36 deletions(-) rename src/Serilog.AspNetCore/{ => AspNetCore}/RequestLoggingOptions.cs (78%) diff --git a/global.json b/global.json index 0a37afd..3cd92d1 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.2.105" + "version": "2.2.402" } -} +} \ No newline at end of file diff --git a/samples/InlineInitializationSample/Startup.cs b/samples/InlineInitializationSample/Startup.cs index 1c8b99f..8de3f04 100644 --- a/samples/InlineInitializationSample/Startup.cs +++ b/samples/InlineInitializationSample/Startup.cs @@ -48,14 +48,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) // Write streamlined request completion events, instead of the more verbose ones from the framework. // To use the default framework request logging instead, remove this line and set the "Microsoft" // level in appsettings.json to "Information". - app.UseSerilogRequestLogging(opts => - { - opts.GetLogEventLevel = statusCode => - statusCode == HttpStatusCode.InternalServerError - ? LogEventLevel.Error - : LogEventLevel.Information; - // OR opts.GetLogEventLevel = _ => LogEventLevel.Information; - }); + app.UseSerilogRequestLogging(); app.UseStaticFiles(); app.UseCookiePolicy(); diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs index 886c31a..d7a9426 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs @@ -12,35 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; -using System.Diagnostics; -using System.Linq; -using System.Net; -using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Serilog.Events; using Serilog.Extensions.Hosting; using Serilog.Parsing; +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; namespace Serilog.AspNetCore { - class RequestLoggingMiddleware + internal class RequestLoggingMiddleware { readonly RequestDelegate _next; readonly DiagnosticContext _diagnosticContext; readonly MessageTemplate _messageTemplate; - readonly Func _getLogEventLevel; - + readonly Func _getLogLevel; static readonly LogEventProperty[] NoProperties = new LogEventProperty[0]; - + public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnosticContext, RequestLoggingOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); _next = next ?? throw new ArgumentNullException(nameof(next)); _diagnosticContext = diagnosticContext ?? throw new ArgumentNullException(nameof(diagnosticContext)); - _getLogEventLevel = options.GetLogEventLevel; + _getLogLevel = options.GetLogLevel; _messageTemplate = new MessageTemplateParser().Parse(options.MessageTemplate); } @@ -71,13 +69,13 @@ public async Task Invoke(HttpContext httpContext) } } - bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector, int statusCode, double elapsedMs, Exception ex) + private bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector, int statusCode, double elapsedMs, Exception ex) { var logger = Log.ForContext(); - var level = _getLogEventLevel((HttpStatusCode)statusCode); - + var level = _getLogLevel(httpContext); + if (!logger.IsEnabled(level)) return false; - + if (!collector.TryComplete(out var collectedProperties)) collectedProperties = NoProperties; diff --git a/src/Serilog.AspNetCore/RequestLoggingOptions.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs similarity index 78% rename from src/Serilog.AspNetCore/RequestLoggingOptions.cs rename to src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs index 949eb36..276993c 100644 --- a/src/Serilog.AspNetCore/RequestLoggingOptions.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +using Microsoft.AspNetCore.Http; using Serilog.Events; using System; -using System.Net; -namespace Serilog +namespace Serilog.AspNetCore { /// - /// Contains options for the Serilog.AspNetCore.RequestLoggingMiddleware. + /// Contains options for the . /// public class RequestLoggingOptions { @@ -35,13 +35,13 @@ public class RequestLoggingOptions public string MessageTemplate { get; set; } /// - /// Gets or sets the function returning the LogEventLevel based on the HttpStatusCode. + /// Gets or sets the function returning the based on the current . /// The default behavior returns LogEventLevel.Error when HttpStatusCode is greater than 499 /// /// - /// The function returning the LogEventLevel. + /// The function returning the . /// - public Func GetLogEventLevel { get; set; } + public Func GetLogLevel { get; set; } internal RequestLoggingOptions() { } } diff --git a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs index 237b2e8..b7af86b 100644 --- a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs +++ b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs @@ -15,6 +15,7 @@ using System; using System.Net; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Serilog.AspNetCore; using Serilog.Events; @@ -29,8 +30,8 @@ public static class SerilogApplicationBuilderExtensions const string DefaultRequestCompletionMessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms"; - static readonly Func DefaultGetLogEventLevel = - s => (int) s > 499 ? LogEventLevel.Error : LogEventLevel.Information; + static Func DefaultGetLogLevel = + ctx => ctx.Response.StatusCode > 499 ? LogEventLevel.Error : LogEventLevel.Information; /// /// Adds middleware for streamlined request logging. Instead of writing HTTP request information @@ -60,7 +61,7 @@ public static IApplicationBuilder UseSerilogRequestLogging( /// in Startup.cs before any handlers whose activities should be logged. /// /// The application builder. - /// An System.Action`1 to configure the provided . + /// A to configure the provided . /// The application builder. public static IApplicationBuilder UseSerilogRequestLogging( this IApplicationBuilder app, @@ -70,15 +71,15 @@ public static IApplicationBuilder UseSerilogRequestLogging( var opts = new RequestLoggingOptions { - GetLogEventLevel = DefaultGetLogEventLevel, + GetLogLevel = DefaultGetLogLevel, MessageTemplate = DefaultRequestCompletionMessageTemplate }; configureOptions?.Invoke(opts); if (opts.MessageTemplate == null) throw new ArgumentException($"{nameof(opts.MessageTemplate)} cannot be null."); - if (opts.GetLogEventLevel == null) - throw new ArgumentException($"{nameof(opts.GetLogEventLevel)} cannot be null."); + if (opts.GetLogLevel == null) + throw new ArgumentException($"{nameof(opts.GetLogLevel)} cannot be null."); return app.UseMiddleware(opts); } From beab81c69095ed7b80fc17eff0f683ac5b6c68fb Mon Sep 17 00:00:00 2001 From: Sebastien Roche Date: Tue, 17 Sep 2019 16:25:47 +0800 Subject: [PATCH 3/5] FIX: rollback sdk version to fix the ci --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 3cd92d1..2be3e86 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.2.402" + "version": "2.2.105" } } \ No newline at end of file From 740fc2fcea94821f5aa811b4ea634039d27f41dd Mon Sep 17 00:00:00 2001 From: Sebastien Roche Date: Wed, 18 Sep 2019 08:42:42 +0800 Subject: [PATCH 4/5] REFACTORING: removed explicit private to stay consistent with coding standards REFACTORING: renamed GetLogLevel to GetLevel --- .../AspNetCore/RequestLoggingMiddleware.cs | 10 +++++----- .../AspNetCore/RequestLoggingOptions.cs | 2 +- .../SerilogApplicationBuilderExtensions.cs | 10 ++++------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs index d7a9426..f90c56d 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs @@ -24,12 +24,12 @@ namespace Serilog.AspNetCore { - internal class RequestLoggingMiddleware + class RequestLoggingMiddleware { readonly RequestDelegate _next; readonly DiagnosticContext _diagnosticContext; readonly MessageTemplate _messageTemplate; - readonly Func _getLogLevel; + readonly Func _getLevel; static readonly LogEventProperty[] NoProperties = new LogEventProperty[0]; public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnosticContext, RequestLoggingOptions options) @@ -38,7 +38,7 @@ public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnost _next = next ?? throw new ArgumentNullException(nameof(next)); _diagnosticContext = diagnosticContext ?? throw new ArgumentNullException(nameof(diagnosticContext)); - _getLogLevel = options.GetLogLevel; + _getLevel = options.GetLevel; _messageTemplate = new MessageTemplateParser().Parse(options.MessageTemplate); } @@ -69,10 +69,10 @@ public async Task Invoke(HttpContext httpContext) } } - private bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector, int statusCode, double elapsedMs, Exception ex) + bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector, int statusCode, double elapsedMs, Exception ex) { var logger = Log.ForContext(); - var level = _getLogLevel(httpContext); + var level = _getLevel(httpContext); if (!logger.IsEnabled(level)) return false; diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs index 276993c..ded5b0b 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs @@ -41,7 +41,7 @@ public class RequestLoggingOptions /// /// The function returning the . /// - public Func GetLogLevel { get; set; } + public Func GetLevel { get; set; } internal RequestLoggingOptions() { } } diff --git a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs index b7af86b..1d1ba26 100644 --- a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs +++ b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs @@ -13,10 +13,8 @@ // limitations under the License. using System; -using System.Net; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Options; using Serilog.AspNetCore; using Serilog.Events; @@ -30,7 +28,7 @@ public static class SerilogApplicationBuilderExtensions const string DefaultRequestCompletionMessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms"; - static Func DefaultGetLogLevel = + static Func DefaultGetLevel = ctx => ctx.Response.StatusCode > 499 ? LogEventLevel.Error : LogEventLevel.Information; /// @@ -71,15 +69,15 @@ public static IApplicationBuilder UseSerilogRequestLogging( var opts = new RequestLoggingOptions { - GetLogLevel = DefaultGetLogLevel, + GetLevel = DefaultGetLevel, MessageTemplate = DefaultRequestCompletionMessageTemplate }; configureOptions?.Invoke(opts); if (opts.MessageTemplate == null) throw new ArgumentException($"{nameof(opts.MessageTemplate)} cannot be null."); - if (opts.GetLogLevel == null) - throw new ArgumentException($"{nameof(opts.GetLogLevel)} cannot be null."); + if (opts.GetLevel == null) + throw new ArgumentException($"{nameof(opts.GetLevel)} cannot be null."); return app.UseMiddleware(opts); } From d4775145637d57760b1abf2a7119c5eccf455813 Mon Sep 17 00:00:00 2001 From: Sebastien Roche Date: Fri, 20 Sep 2019 13:39:47 +0800 Subject: [PATCH 5/5] FIX: modified GetLevel to accept both HttpContext and Exception. This is useful when an exception is thrown but HttpStatusCode is not yet set to 500 InternalServerError FIX: DefaultGetLevel now returns Error if there is an exception OR if StatusCode > 499 --- .../AspNetCore/RequestLoggingMiddleware.cs | 6 +++--- .../AspNetCore/RequestLoggingOptions.cs | 6 +++--- .../SerilogApplicationBuilderExtensions.cs | 8 ++++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs index f90c56d..9089efd 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs @@ -29,7 +29,7 @@ class RequestLoggingMiddleware readonly RequestDelegate _next; readonly DiagnosticContext _diagnosticContext; readonly MessageTemplate _messageTemplate; - readonly Func _getLevel; + readonly Func _getLevel; static readonly LogEventProperty[] NoProperties = new LogEventProperty[0]; public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnosticContext, RequestLoggingOptions options) @@ -72,7 +72,7 @@ public async Task Invoke(HttpContext httpContext) bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector, int statusCode, double elapsedMs, Exception ex) { var logger = Log.ForContext(); - var level = _getLevel(httpContext); + var level = _getLevel(httpContext, ex); if (!logger.IsEnabled(level)) return false; @@ -98,7 +98,7 @@ static double GetElapsedMilliseconds(long start, long stop) { return (stop - start) * 1000 / (double)Stopwatch.Frequency; } - + static string GetPath(HttpContext httpContext) { return httpContext.Features.Get()?.RawTarget ?? httpContext.Request.Path.ToString(); diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs index ded5b0b..c353e05 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs @@ -35,13 +35,13 @@ public class RequestLoggingOptions public string MessageTemplate { get; set; } /// - /// Gets or sets the function returning the based on the current . - /// The default behavior returns LogEventLevel.Error when HttpStatusCode is greater than 499 + /// Gets or sets the function returning the based on the and on the if something wrong happend + /// The default behavior returns LogEventLevel.Error when HttpStatusCode is greater than 499 or if Exception is not null. /// /// /// The function returning the . /// - public Func GetLevel { get; set; } + public Func GetLevel { get; set; } internal RequestLoggingOptions() { } } diff --git a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs index 1d1ba26..e1e2f53 100644 --- a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs +++ b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs @@ -28,8 +28,12 @@ public static class SerilogApplicationBuilderExtensions const string DefaultRequestCompletionMessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms"; - static Func DefaultGetLevel = - ctx => ctx.Response.StatusCode > 499 ? LogEventLevel.Error : LogEventLevel.Information; + static Func DefaultGetLevel = + (ctx, ex) => ex != null + ? LogEventLevel.Error + : ctx.Response.StatusCode > 499 + ? LogEventLevel.Error + : LogEventLevel.Information; /// /// Adds middleware for streamlined request logging. Instead of writing HTTP request information