Skip to content

Commit 5341d20

Browse files
author
Sebastien Roche
committed
FEATURE: add ability to customize the LogEventLevel used by the middleware
FEATUREL add new dependency injection overloads to offer more flexibility while configuring options
1 parent 77c2c1a commit 5341d20

File tree

4 files changed

+81
-16
lines changed

4 files changed

+81
-16
lines changed

samples/InlineInitializationSample/Startup.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
using Microsoft.AspNetCore.Builder;
1+
using System.Net;
2+
using Microsoft.AspNetCore.Builder;
23
using Microsoft.AspNetCore.Hosting;
34
using Microsoft.AspNetCore.Http;
45
using Microsoft.AspNetCore.Mvc;
56
using Microsoft.Extensions.Configuration;
67
using Microsoft.Extensions.DependencyInjection;
78
using Serilog;
9+
using Serilog.Events;
810

911
namespace InlineInitializationSample
1012
{
@@ -46,7 +48,14 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
4648
// Write streamlined request completion events, instead of the more verbose ones from the framework.
4749
// To use the default framework request logging instead, remove this line and set the "Microsoft"
4850
// level in appsettings.json to "Information".
49-
app.UseSerilogRequestLogging();
51+
app.UseSerilogRequestLogging(opts =>
52+
{
53+
opts.GetLogEventLevel = statusCode =>
54+
statusCode == HttpStatusCode.InternalServerError
55+
? LogEventLevel.Error
56+
: LogEventLevel.Information;
57+
// OR opts.GetLogEventLevel = _ => LogEventLevel.Information;
58+
});
5059

5160
app.UseStaticFiles();
5261
app.UseCookiePolicy();

src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using System;
1616
using System.Diagnostics;
1717
using System.Linq;
18+
using System.Net;
1819
using System.Threading.Tasks;
1920
using Microsoft.AspNetCore.Http;
2021
using Microsoft.AspNetCore.Http.Features;
@@ -29,15 +30,17 @@ class RequestLoggingMiddleware
2930
readonly RequestDelegate _next;
3031
readonly DiagnosticContext _diagnosticContext;
3132
readonly MessageTemplate _messageTemplate;
33+
readonly Func<HttpStatusCode, LogEventLevel> _getLogEventLevel;
3234

3335
static readonly LogEventProperty[] NoProperties = new LogEventProperty[0];
34-
36+
3537
public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnosticContext, RequestLoggingOptions options)
3638
{
3739
if (options == null) throw new ArgumentNullException(nameof(options));
3840
_next = next ?? throw new ArgumentNullException(nameof(next));
3941
_diagnosticContext = diagnosticContext ?? throw new ArgumentNullException(nameof(diagnosticContext));
4042

43+
_getLogEventLevel = options.GetLogEventLevel;
4144
_messageTemplate = new MessageTemplateParser().Parse(options.MessageTemplate);
4245
}
4346

@@ -71,8 +74,8 @@ public async Task Invoke(HttpContext httpContext)
7174
bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector, int statusCode, double elapsedMs, Exception ex)
7275
{
7376
var logger = Log.ForContext<RequestLoggingMiddleware>();
74-
var level = statusCode > 499 ? LogEventLevel.Error : LogEventLevel.Information;
75-
77+
var level = _getLogEventLevel((HttpStatusCode)statusCode);
78+
7679
if (!logger.IsEnabled(level)) return false;
7780

7881
if (!collector.TryComplete(out var collectedProperties))

src/Serilog.AspNetCore/RequestLoggingOptions.cs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,37 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using Serilog.Events;
1516
using System;
17+
using System.Net;
1618

1719
namespace Serilog
1820
{
19-
class RequestLoggingOptions
21+
/// <summary>
22+
/// Contains options for the Serilog.AspNetCore.RequestLoggingMiddleware.
23+
/// </summary>
24+
public class RequestLoggingOptions
2025
{
21-
public string MessageTemplate { get; }
26+
/// <summary>
27+
/// Gets or sets the message template. The default value is
28+
/// <c>"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms"</c>. The
29+
/// template can contain any of the placeholders from the default template, names of properties
30+
/// added by ASP.NET Core, and names of properties added to the <see cref="IDiagnosticContext"/>.
31+
/// </summary>
32+
/// <value>
33+
/// The message template.
34+
/// </value>
35+
public string MessageTemplate { get; set; }
2236

23-
public RequestLoggingOptions(string messageTemplate)
24-
{
25-
MessageTemplate = messageTemplate ?? throw new ArgumentNullException(nameof(messageTemplate));
26-
}
37+
/// <summary>
38+
/// Gets or sets the function returning the LogEventLevel based on the HttpStatusCode.
39+
/// The default behavior returns LogEventLevel.Error when HttpStatusCode is greater than 499
40+
/// </summary>
41+
/// <value>
42+
/// The function returning the LogEventLevel.
43+
/// </value>
44+
public Func<HttpStatusCode, LogEventLevel> GetLogEventLevel { get; set; }
45+
46+
internal RequestLoggingOptions() { }
2747
}
28-
}
48+
}

src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
// limitations under the License.
1414

1515
using System;
16+
using System.Net;
1617
using Microsoft.AspNetCore.Builder;
18+
using Microsoft.Extensions.Options;
1719
using Serilog.AspNetCore;
20+
using Serilog.Events;
1821

1922
namespace Serilog
2023
{
@@ -26,6 +29,9 @@ public static class SerilogApplicationBuilderExtensions
2629
const string DefaultRequestCompletionMessageTemplate =
2730
"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms";
2831

32+
static readonly Func<HttpStatusCode, LogEventLevel> DefaultGetLogEventLevel =
33+
s => (int) s > 499 ? LogEventLevel.Error : LogEventLevel.Information;
34+
2935
/// <summary>
3036
/// Adds middleware for streamlined request logging. Instead of writing HTTP request information
3137
/// like method, path, timing, status code and exception details
@@ -43,11 +49,38 @@ public static class SerilogApplicationBuilderExtensions
4349
/// <returns>The application builder.</returns>
4450
public static IApplicationBuilder UseSerilogRequestLogging(
4551
this IApplicationBuilder app,
46-
string messageTemplate = DefaultRequestCompletionMessageTemplate)
52+
string messageTemplate)
53+
=> app.UseSerilogRequestLogging(opts => opts.MessageTemplate = messageTemplate);
54+
55+
/// <summary>
56+
/// Adds middleware for streamlined request logging. Instead of writing HTTP request information
57+
/// like method, path, timing, status code and exception details
58+
/// in several events, this middleware collects information during the request (including from
59+
/// <see cref="IDiagnosticContext"/>), and writes a single event at request completion. Add this
60+
/// in <c>Startup.cs</c> before any handlers whose activities should be logged.
61+
/// </summary>
62+
/// <param name="app">The application builder.</param>
63+
/// <param name="configureOptions"> An System.Action`1 to configure the provided <see cref="Serilog.RequestLoggingOptions" />.</param>
64+
/// <returns>The application builder.</returns>
65+
public static IApplicationBuilder UseSerilogRequestLogging(
66+
this IApplicationBuilder app,
67+
Action<RequestLoggingOptions> configureOptions = null)
4768
{
4869
if (app == null) throw new ArgumentNullException(nameof(app));
49-
if (messageTemplate == null) throw new ArgumentNullException(nameof(messageTemplate));
50-
return app.UseMiddleware<RequestLoggingMiddleware>(new RequestLoggingOptions(messageTemplate));
70+
71+
var opts = new RequestLoggingOptions
72+
{
73+
GetLogEventLevel = DefaultGetLogEventLevel,
74+
MessageTemplate = DefaultRequestCompletionMessageTemplate
75+
};
76+
configureOptions?.Invoke(opts);
77+
78+
if (opts.MessageTemplate == null)
79+
throw new ArgumentException($"{nameof(opts.MessageTemplate)} cannot be null.");
80+
if (opts.GetLogEventLevel == null)
81+
throw new ArgumentException($"{nameof(opts.GetLogEventLevel)} cannot be null.");
82+
83+
return app.UseMiddleware<RequestLoggingMiddleware>(opts);
5184
}
5285
}
53-
}
86+
}

0 commit comments

Comments
 (0)