Skip to content

Commit 25af04c

Browse files
authored
Merge pull request #132 from seroche/dev
Ability to customize LogEventLevel used in UseSerilogRequestLogging middleware
2 parents e6e14e6 + d477514 commit 25af04c

File tree

6 files changed

+101
-42
lines changed

6 files changed

+101
-42
lines changed

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"sdk": {
33
"version": "2.2.105"
44
}
5-
}
5+
}

samples/InlineInitializationSample/Startup.cs

Lines changed: 3 additions & 1 deletion
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
{

src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs

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

15-
using System;
16-
using System.Diagnostics;
17-
using System.Linq;
18-
using System.Threading.Tasks;
1915
using Microsoft.AspNetCore.Http;
2016
using Microsoft.AspNetCore.Http.Features;
2117
using Serilog.Events;
2218
using Serilog.Extensions.Hosting;
2319
using Serilog.Parsing;
20+
using System;
21+
using System.Diagnostics;
22+
using System.Linq;
23+
using System.Threading.Tasks;
2424

2525
namespace Serilog.AspNetCore
2626
{
@@ -29,7 +29,7 @@ class RequestLoggingMiddleware
2929
readonly RequestDelegate _next;
3030
readonly DiagnosticContext _diagnosticContext;
3131
readonly MessageTemplate _messageTemplate;
32-
32+
readonly Func<HttpContext, Exception, LogEventLevel> _getLevel;
3333
static readonly LogEventProperty[] NoProperties = new LogEventProperty[0];
3434

3535
public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnosticContext, RequestLoggingOptions options)
@@ -38,6 +38,7 @@ public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnost
3838
_next = next ?? throw new ArgumentNullException(nameof(next));
3939
_diagnosticContext = diagnosticContext ?? throw new ArgumentNullException(nameof(diagnosticContext));
4040

41+
_getLevel = options.GetLevel;
4142
_messageTemplate = new MessageTemplateParser().Parse(options.MessageTemplate);
4243
}
4344

@@ -71,10 +72,10 @@ public async Task Invoke(HttpContext httpContext)
7172
bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector, int statusCode, double elapsedMs, Exception ex)
7273
{
7374
var logger = Log.ForContext<RequestLoggingMiddleware>();
74-
var level = statusCode > 499 ? LogEventLevel.Error : LogEventLevel.Information;
75+
var level = _getLevel(httpContext, ex);
7576

7677
if (!logger.IsEnabled(level)) return false;
77-
78+
7879
if (!collector.TryComplete(out var collectedProperties))
7980
collectedProperties = NoProperties;
8081

@@ -97,7 +98,7 @@ static double GetElapsedMilliseconds(long start, long stop)
9798
{
9899
return (stop - start) * 1000 / (double)Stopwatch.Frequency;
99100
}
100-
101+
101102
static string GetPath(HttpContext httpContext)
102103
{
103104
return httpContext.Features.Get<IHttpRequestFeature>()?.RawTarget ?? httpContext.Request.Path.ToString();
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2019 Serilog Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using Microsoft.AspNetCore.Http;
16+
using Serilog.Events;
17+
using System;
18+
19+
namespace Serilog.AspNetCore
20+
{
21+
/// <summary>
22+
/// Contains options for the <see cref="Serilog.AspNetCore.RequestLoggingMiddleware"/>.
23+
/// </summary>
24+
public class RequestLoggingOptions
25+
{
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; }
36+
37+
/// <summary>
38+
/// Gets or sets the function returning the <see cref="LogEventLevel"/> based on the <see cref="HttpContext"/> and on the <see cref="Exception" /> if something wrong happend
39+
/// The default behavior returns LogEventLevel.Error when HttpStatusCode is greater than 499 or if Exception is not null.
40+
/// </summary>
41+
/// <value>
42+
/// The function returning the <see cref="LogEventLevel"/>.
43+
/// </value>
44+
public Func<HttpContext, Exception, LogEventLevel> GetLevel { get; set; }
45+
46+
internal RequestLoggingOptions() { }
47+
}
48+
}

src/Serilog.AspNetCore/RequestLoggingOptions.cs

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414

1515
using System;
1616
using Microsoft.AspNetCore.Builder;
17+
using Microsoft.AspNetCore.Http;
1718
using Serilog.AspNetCore;
19+
using Serilog.Events;
1820

1921
namespace Serilog
2022
{
@@ -26,6 +28,13 @@ public static class SerilogApplicationBuilderExtensions
2628
const string DefaultRequestCompletionMessageTemplate =
2729
"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms";
2830

31+
static Func<HttpContext, Exception, LogEventLevel> DefaultGetLevel =
32+
(ctx, ex) => ex != null
33+
? LogEventLevel.Error
34+
: ctx.Response.StatusCode > 499
35+
? LogEventLevel.Error
36+
: LogEventLevel.Information;
37+
2938
/// <summary>
3039
/// Adds middleware for streamlined request logging. Instead of writing HTTP request information
3140
/// like method, path, timing, status code and exception details
@@ -43,11 +52,38 @@ public static class SerilogApplicationBuilderExtensions
4352
/// <returns>The application builder.</returns>
4453
public static IApplicationBuilder UseSerilogRequestLogging(
4554
this IApplicationBuilder app,
46-
string messageTemplate = DefaultRequestCompletionMessageTemplate)
55+
string messageTemplate)
56+
=> app.UseSerilogRequestLogging(opts => opts.MessageTemplate = messageTemplate);
57+
58+
/// <summary>
59+
/// Adds middleware for streamlined request logging. Instead of writing HTTP request information
60+
/// like method, path, timing, status code and exception details
61+
/// in several events, this middleware collects information during the request (including from
62+
/// <see cref="IDiagnosticContext"/>), and writes a single event at request completion. Add this
63+
/// in <c>Startup.cs</c> before any handlers whose activities should be logged.
64+
/// </summary>
65+
/// <param name="app">The application builder.</param>
66+
/// <param name="configureOptions">A <see cref="System.Action{T}" /> to configure the provided <see cref="RequestLoggingOptions" />.</param>
67+
/// <returns>The application builder.</returns>
68+
public static IApplicationBuilder UseSerilogRequestLogging(
69+
this IApplicationBuilder app,
70+
Action<RequestLoggingOptions> configureOptions = null)
4771
{
4872
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));
73+
74+
var opts = new RequestLoggingOptions
75+
{
76+
GetLevel = DefaultGetLevel,
77+
MessageTemplate = DefaultRequestCompletionMessageTemplate
78+
};
79+
configureOptions?.Invoke(opts);
80+
81+
if (opts.MessageTemplate == null)
82+
throw new ArgumentException($"{nameof(opts.MessageTemplate)} cannot be null.");
83+
if (opts.GetLevel == null)
84+
throw new ArgumentException($"{nameof(opts.GetLevel)} cannot be null.");
85+
86+
return app.UseMiddleware<RequestLoggingMiddleware>(opts);
5187
}
5288
}
53-
}
89+
}

0 commit comments

Comments
 (0)