From 487109638612611520591cbff446837b843b1e0a Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 19 Aug 2019 08:28:40 +1000 Subject: [PATCH 01/16] Sample conversion WIP --- global.json | 2 +- .../EarlyInitializationSample.csproj | 10 +----- samples/EarlyInitializationSample/Program.cs | 14 ++++++-- samples/EarlyInitializationSample/Startup.cs | 32 ++++--------------- 4 files changed, 19 insertions(+), 39 deletions(-) diff --git a/global.json b/global.json index 0a37afd..4201a8f 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.2.105" + "version": "3.0.100-preview8-013656" } } diff --git a/samples/EarlyInitializationSample/EarlyInitializationSample.csproj b/samples/EarlyInitializationSample/EarlyInitializationSample.csproj index bae7e3f..0b71549 100644 --- a/samples/EarlyInitializationSample/EarlyInitializationSample.csproj +++ b/samples/EarlyInitializationSample/EarlyInitializationSample.csproj @@ -1,19 +1,11 @@  - netcoreapp2.2 - InProcess + netcoreapp3.0 - - - - - - - diff --git a/samples/EarlyInitializationSample/Program.cs b/samples/EarlyInitializationSample/Program.cs index e8fda83..247e6ee 100644 --- a/samples/EarlyInitializationSample/Program.cs +++ b/samples/EarlyInitializationSample/Program.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; using Serilog; namespace EarlyInitializationSample @@ -31,7 +32,7 @@ public static int Main(string[] args) { Log.Information("Getting the motors running..."); - BuildWebHost(args).Run(); + CreateHostBuilder(args).Build().Run(); return 0; } @@ -49,8 +50,15 @@ public static int Main(string[] args) public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup() - .UseConfiguration(Configuration) - .UseSerilog() .Build(); + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }) + .UseConfiguration(Configuration) + .UseSerilog(); } } diff --git a/samples/EarlyInitializationSample/Startup.cs b/samples/EarlyInitializationSample/Startup.cs index 418f352..d582e20 100644 --- a/samples/EarlyInitializationSample/Startup.cs +++ b/samples/EarlyInitializationSample/Startup.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; +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 Microsoft.Extensions.Hosting; using Serilog; namespace EarlyInitializationSample @@ -21,22 +16,11 @@ public Startup(IConfiguration configuration) public IConfiguration Configuration { get; } - // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.Configure(options => - { - // This lambda determines whether user consent for non-essential cookies is needed for a given request. - options.CheckConsentNeeded = context => true; - options.MinimumSameSitePolicy = SameSiteMode.None; - }); - - - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { @@ -53,14 +37,10 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) app.UseSerilogRequestLogging(); app.UseStaticFiles(); - app.UseCookiePolicy(); + + app.UseRouting(); - app.UseMvc(routes => - { - routes.MapRoute( - name: "default", - template: "{controller=Home}/{action=Index}/{id?}"); - }); + app.UseEndpoints(endpoints => endpoints.MapControllers()); } } } From ba4f44e03afe66d581296627744677a5d98101c1 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 19 Aug 2019 10:46:49 +1000 Subject: [PATCH 02/16] Install SDK in Setup.ps1 --- Setup.ps1 | 11 +++++++++++ appveyor.yml | 2 +- serilog-aspnetcore.sln | 5 +++-- 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 Setup.ps1 diff --git a/Setup.ps1 b/Setup.ps1 new file mode 100644 index 0000000..880a07a --- /dev/null +++ b/Setup.ps1 @@ -0,0 +1,11 @@ +$ErrorActionPreference = "Stop" + +$RequiredDotnetVersion = $(cat ./global.json | convertfrom-json).sdk.version + +mkdir "./build" + +Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile "./build/installcli.ps1" +& ./build/installcli.ps1 -InstallDir "$pwd/.dotnetcli" -NoPath -Version $RequiredDotnetVersion +if ($LASTEXITCODE) { exit 1 } + +$env:Path = "$pwd/.dotnetcli;$env:Path" diff --git a/appveyor.yml b/appveyor.yml index 8889af6..ef82a65 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ version: '{build}' skip_tags: true image: Visual Studio 2017 install: - - ps: mkdir -Force ".\build\" | Out-Null +- ps: ./Setup.ps1 build_script: - ps: ./Build.ps1 test: off diff --git a/serilog-aspnetcore.sln b/serilog-aspnetcore.sln index a50ef98..920326e 100644 --- a/serilog-aspnetcore.sln +++ b/serilog-aspnetcore.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26730.12 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29209.62 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A1893BD1-333D-4DFE-A0F0-DDBB2FE526E0}" EndProject @@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{9C21B9 global.json = global.json README.md = README.md assets\Serilog.snk = assets\Serilog.snk + Setup.ps1 = Setup.ps1 EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.AspNetCore", "src\Serilog.AspNetCore\Serilog.AspNetCore.csproj", "{0549D23F-986B-4FB2-BACE-16FD7A7BC9EF}" From 7740fbea06ceadaf2a1ea72343bd4780b2a49c84 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 28 Aug 2019 10:12:48 +1000 Subject: [PATCH 03/16] Dev version bump [skip ci] --- src/Serilog.AspNetCore/Serilog.AspNetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj b/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj index b3bc048..46d4f45 100644 --- a/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj +++ b/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj @@ -2,7 +2,7 @@ Serilog support for ASP.NET Core logging - 3.0.0 + 3.0.1 Microsoft;Serilog Contributors netstandard2.0 true From 11bdd7e4e4ceada1d63c9b89243ff8fe4047138a Mon Sep 17 00:00:00 2001 From: Adam Lith Date: Tue, 3 Sep 2019 10:43:31 +0200 Subject: [PATCH 04/16] Adding source context for the logging in RequestLoggingMiddleware. Fixing Issue #123 --- .../AspNetCore/RequestLoggingMiddleware.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs index 797d896..db32cbe 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs @@ -70,9 +70,10 @@ 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; - if (!Log.IsEnabled(level)) return false; + if (!logger.IsEnabled(level)) return false; if (!collector.TryComplete(out var collectedProperties)) collectedProperties = NoProperties; @@ -87,7 +88,7 @@ bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector }); var evt = new LogEvent(DateTimeOffset.Now, level, ex, _messageTemplate, properties); - Log.Write(evt); + logger.Write(evt); return false; } From 77c2c1afebc2ee57b676b8701e0f1b077bfad2d8 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Tue, 10 Sep 2019 09:49:25 +1000 Subject: [PATCH 05/16] Changes are now tracked through /releases; no need for CHANGES.md [skip ci] --- CHANGES.md | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 CHANGES.md diff --git a/CHANGES.md b/CHANGES.md deleted file mode 100644 index be62715..0000000 --- a/CHANGES.md +++ /dev/null @@ -1,4 +0,0 @@ -2.0.0 - - * Initial version for ASP.NET Core 2. - From 5341d20bd203c0f9c3fee362e2ba7a9d9b4d2de8 Mon Sep 17 00:00:00 2001 From: Sebastien Roche Date: Tue, 17 Sep 2019 14:59:07 +0800 Subject: [PATCH 06/16] 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 07/16] 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 08/16] 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 09/16] 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 10/16] 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 From 390fa721db83404b4ab7cd0ab1ba96723cb4664a Mon Sep 17 00:00:00 2001 From: DavidCoghlan <42351331+DavidCoghlan@users.noreply.github.com> Date: Wed, 25 Sep 2019 18:20:05 +0100 Subject: [PATCH 11/16] Update docs on disabling built-in logging The current documentation recommends overriding the logging level for the entire Microsoft namespace, but this also suppresses logging for other Microsoft products, such as Entity Framework Core. Suggest updating this to recommend overriding Microsoft.AspNetCore instead. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8732504..00678bb 100644 --- a/README.md +++ b/README.md @@ -109,10 +109,10 @@ Or [as JSON](https://github.com/serilog/serilog-formatting-compact): } ``` -To enable the middleware, first change the minimum level for `Microsoft` to `Warning` in your logger configuration or _appsettings.json_ file: +To enable the middleware, first change the minimum level for `Microsoft.AspNetCore` to `Warning` in your logger configuration or _appsettings.json_ file: ```csharp - .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) ``` Then, in your application's _Startup.cs_, add the middleware with `UseSerilogRequestLogging()`: From b03e9572ac669e47edf2ee0a9c7f7ee8adc82faa Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 2 Oct 2019 21:58:11 +1000 Subject: [PATCH 12/16] Use the final 3.0.100 SDK --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 4201a8f..79422f0 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "3.0.100-preview8-013656" + "version": "3.0.100" } } From ed55d3d4344b835c3ea1d70825fd36c3a8dda375 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 2 Oct 2019 22:05:12 +1000 Subject: [PATCH 13/16] Include 'double elapsedMs' in the function signature of the GetLevel delegate --- .../AspNetCore/RequestLoggingMiddleware.cs | 4 ++-- .../AspNetCore/RequestLoggingOptions.cs | 8 +++++--- .../SerilogApplicationBuilderExtensions.cs | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs index 9089efd..954b326 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, ex); + var level = _getLevel(httpContext, elapsedMs, ex); if (!logger.IsEnabled(level)) return false; diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs index c353e05..3a4127a 100644 --- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs +++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs @@ -35,13 +35,15 @@ public class RequestLoggingOptions public string MessageTemplate { get; set; } /// - /// 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. + /// Gets or sets the function returning the based on the , the number of + /// elapsed milliseconds required for handling the request, and an if one was thrown. + /// The default behavior returns when the response status code is greater than 499 or if the + /// 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 e1e2f53..1211453 100644 --- a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs +++ b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs @@ -28,8 +28,8 @@ public static class SerilogApplicationBuilderExtensions const string DefaultRequestCompletionMessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms"; - static Func DefaultGetLevel = - (ctx, ex) => ex != null + static readonly Func DefaultGetLevel = + (ctx, _, ex) => ex != null ? LogEventLevel.Error : ctx.Response.StatusCode > 499 ? LogEventLevel.Error From 39473b8cc9f536e6aaccfa40c145884d48a58323 Mon Sep 17 00:00:00 2001 From: Scott Batary Date: Wed, 2 Oct 2019 12:34:35 -0500 Subject: [PATCH 14/16] Fix a typo in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00678bb..4c324f6 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ Finally, pass the provider collection into `UseSerilog()`: Providers registered in _Startup.cs_ with `AddLogging()` will then receive events from Serilog. -**Using iniline initialization:** +**Using inline initialization:** If [inline initialization](#inline-initialization) is used, providers can be enabled by adding `writeToProviders: true` to the `UseSerilog()` method call: From af412eeac21d1b343580a10205f65e916cac9d1b Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 7 Oct 2019 15:59:19 +1000 Subject: [PATCH 15/16] Minor version bump, new features coming --- src/Serilog.AspNetCore/Serilog.AspNetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj b/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj index 46d4f45..ed44508 100644 --- a/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj +++ b/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj @@ -2,7 +2,7 @@ Serilog support for ASP.NET Core logging - 3.0.1 + 3.1.0 Microsoft;Serilog Contributors netstandard2.0 true From ac78f96fc0afb8a4dbc8a4af1d570d68fd34d661 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 7 Oct 2019 16:04:12 +1000 Subject: [PATCH 16/16] Slight reformatting of DefaultGetLevel --- src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs index 1211453..838fd94 100644 --- a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs +++ b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs @@ -28,8 +28,8 @@ public static class SerilogApplicationBuilderExtensions const string DefaultRequestCompletionMessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms"; - static readonly Func DefaultGetLevel = - (ctx, _, ex) => ex != null + static LogEventLevel DefaultGetLevel(HttpContext ctx, double _, Exception ex) => + ex != null ? LogEventLevel.Error : ctx.Response.StatusCode > 499 ? LogEventLevel.Error