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.
-
diff --git a/README.md b/README.md
index 8732504..4c324f6 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()`:
@@ -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:
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/global.json b/global.json
index 0a37afd..2223a05 100644
--- a/global.json
+++ b/global.json
@@ -1,5 +1,5 @@
{
"sdk": {
- "version": "2.2.105"
+ "version": "3.0.100"
}
-}
+}
\ No newline at end of file
diff --git a/samples/EarlyInitializationSample/EarlyInitializationSample.csproj b/samples/EarlyInitializationSample/EarlyInitializationSample.csproj
index aa91d7f..0b71549 100644
--- a/samples/EarlyInitializationSample/EarlyInitializationSample.csproj
+++ b/samples/EarlyInitializationSample/EarlyInitializationSample.csproj
@@ -1,17 +1,11 @@
- netcoreapp2.2
- InProcess
+ netcoreapp3.0
-
-
-
-
-
diff --git a/samples/EarlyInitializationSample/Program.cs b/samples/EarlyInitializationSample/Program.cs
index 407d45e..284a26b 100644
--- a/samples/EarlyInitializationSample/Program.cs
+++ b/samples/EarlyInitializationSample/Program.cs
@@ -1,8 +1,8 @@
using System;
using System.IO;
-using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
using Serilog;
namespace EarlyInitializationSample
@@ -23,16 +23,14 @@ public static int Main(string[] args)
.Enrich.FromLogContext()
.WriteTo.Debug()
.WriteTo.Console(
- // {Properties:j} added:
- outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} " +
- "{Properties:j}{NewLine}{Exception}")
+ outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}")
.CreateLogger();
try
{
Log.Information("Getting the motors running...");
- BuildWebHost(args).Run();
+ CreateHostBuilder(args).Build().Run();
return 0;
}
@@ -47,11 +45,12 @@ 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();
+ })
+ .UseSerilog();
}
}
diff --git a/samples/EarlyInitializationSample/Startup.cs b/samples/EarlyInitializationSample/Startup.cs
index 42e25e0..502c133 100644
--- a/samples/EarlyInitializationSample/Startup.cs
+++ b/samples/EarlyInitializationSample/Startup.cs
@@ -1,38 +1,19 @@
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
{
public class Startup
{
- public Startup(IConfiguration configuration)
- {
- Configuration = 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);
+ services.AddControllersWithViews();
}
- // 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())
{
@@ -41,21 +22,23 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
else
{
app.UseExceptionHandler("/Home/Error");
+ app.UseHsts();
}
+ app.UseStaticFiles();
+
// 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.UseStaticFiles();
- app.UseCookiePolicy();
+ app.UseRouting();
- app.UseMvc(routes =>
+ app.UseEndpoints(endpoints =>
{
- routes.MapRoute(
+ endpoints.MapControllerRoute(
name: "default",
- template: "{controller=Home}/{action=Index}/{id?}");
+ pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
diff --git a/samples/InlineInitializationSample/InlineInitializationSample.csproj b/samples/InlineInitializationSample/InlineInitializationSample.csproj
index aa91d7f..0b71549 100644
--- a/samples/InlineInitializationSample/InlineInitializationSample.csproj
+++ b/samples/InlineInitializationSample/InlineInitializationSample.csproj
@@ -1,17 +1,11 @@
- netcoreapp2.2
- InProcess
+ netcoreapp3.0
-
-
-
-
-
diff --git a/samples/InlineInitializationSample/Program.cs b/samples/InlineInitializationSample/Program.cs
index 18bca7d..9cf2e42 100644
--- a/samples/InlineInitializationSample/Program.cs
+++ b/samples/InlineInitializationSample/Program.cs
@@ -1,5 +1,5 @@
-using Microsoft.AspNetCore;
-using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
using Serilog;
namespace InlineInitializationSample
@@ -8,19 +8,20 @@ public class Program
{
public static void Main(string[] args)
{
- CreateWebHostBuilder(args).Build().Run();
+ CreateHostBuilder(args).Build().Run();
}
- public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
- .UseStartup()
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ })
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
.Enrich.FromLogContext()
.WriteTo.Debug()
.WriteTo.Console(
- // {Properties:j} added:
- outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} " +
- "{Properties:j}{NewLine}{Exception}"));
+ outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"));
}
}
diff --git a/samples/InlineInitializationSample/Startup.cs b/samples/InlineInitializationSample/Startup.cs
index 87d3a0c..82f3bcd 100644
--- a/samples/InlineInitializationSample/Startup.cs
+++ b/samples/InlineInitializationSample/Startup.cs
@@ -1,38 +1,21 @@
-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 Microsoft.Extensions.Hosting;
using Serilog;
+using Serilog.Events;
namespace InlineInitializationSample
{
public class Startup
{
- public Startup(IConfiguration configuration)
- {
- Configuration = 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);
+ services.AddControllersWithViews();
}
- // 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())
{
@@ -41,21 +24,23 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
else
{
app.UseExceptionHandler("/Home/Error");
+ app.UseHsts();
}
+ app.UseStaticFiles();
+
// 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.UseStaticFiles();
- app.UseCookiePolicy();
+ app.UseRouting();
- app.UseMvc(routes =>
+ app.UseEndpoints(endpoints =>
{
- routes.MapRoute(
+ endpoints.MapControllerRoute(
name: "default",
- template: "{controller=Home}/{action=Index}/{id?}");
+ pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
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}"
diff --git a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs
index 797d896..954b326 100644
--- a/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs
+++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingMiddleware.cs
@@ -12,15 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using System;
-using System.Diagnostics;
-using System.Linq;
-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
{
@@ -29,7 +29,7 @@ class RequestLoggingMiddleware
readonly RequestDelegate _next;
readonly DiagnosticContext _diagnosticContext;
readonly MessageTemplate _messageTemplate;
-
+ readonly Func _getLevel;
static readonly LogEventProperty[] NoProperties = new LogEventProperty[0];
public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnosticContext, RequestLoggingOptions options)
@@ -38,6 +38,7 @@ public RequestLoggingMiddleware(RequestDelegate next, DiagnosticContext diagnost
_next = next ?? throw new ArgumentNullException(nameof(next));
_diagnosticContext = diagnosticContext ?? throw new ArgumentNullException(nameof(diagnosticContext));
+ _getLevel = options.GetLevel;
_messageTemplate = new MessageTemplateParser().Parse(options.MessageTemplate);
}
@@ -70,10 +71,11 @@ public async Task Invoke(HttpContext httpContext)
bool LogCompletion(HttpContext httpContext, DiagnosticContextCollector collector, int statusCode, double elapsedMs, Exception ex)
{
- var level = statusCode > 499 ? LogEventLevel.Error : LogEventLevel.Information;
+ var logger = Log.ForContext();
+ var level = _getLevel(httpContext, elapsedMs, ex);
+
+ if (!logger.IsEnabled(level)) return false;
- if (!Log.IsEnabled(level)) return false;
-
if (!collector.TryComplete(out var collectedProperties))
collectedProperties = NoProperties;
@@ -87,7 +89,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;
}
@@ -96,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
new file mode 100644
index 0000000..3a4127a
--- /dev/null
+++ b/src/Serilog.AspNetCore/AspNetCore/RequestLoggingOptions.cs
@@ -0,0 +1,50 @@
+// Copyright 2019 Serilog Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Microsoft.AspNetCore.Http;
+using Serilog.Events;
+using System;
+
+namespace Serilog.AspNetCore
+{
+ ///
+ /// Contains options for the .
+ ///
+ public class RequestLoggingOptions
+ {
+ ///
+ /// 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; }
+
+ ///
+ /// 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; }
+
+ internal RequestLoggingOptions() { }
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.AspNetCore/RequestLoggingOptions.cs b/src/Serilog.AspNetCore/RequestLoggingOptions.cs
deleted file mode 100644
index f68cf43..0000000
--- a/src/Serilog.AspNetCore/RequestLoggingOptions.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2019 Serilog Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-
-namespace Serilog
-{
- class RequestLoggingOptions
- {
- public string MessageTemplate { get; }
-
- public RequestLoggingOptions(string messageTemplate)
- {
- MessageTemplate = messageTemplate ?? throw new ArgumentNullException(nameof(messageTemplate));
- }
- }
-}
diff --git a/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj b/src/Serilog.AspNetCore/Serilog.AspNetCore.csproj
index b3bc048..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.0
+ 3.1.0
Microsoft;Serilog Contributors
netstandard2.0
true
diff --git a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs
index 91c7106..838fd94 100644
--- a/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs
+++ b/src/Serilog.AspNetCore/SerilogApplicationBuilderExtensions.cs
@@ -14,7 +14,9 @@
using System;
using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
using Serilog.AspNetCore;
+using Serilog.Events;
namespace Serilog
{
@@ -26,6 +28,13 @@ public static class SerilogApplicationBuilderExtensions
const string DefaultRequestCompletionMessageTemplate =
"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms";
+ static LogEventLevel DefaultGetLevel(HttpContext ctx, double _, Exception 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
/// like method, path, timing, status code and exception details
@@ -43,11 +52,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.
+ /// A 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
+ {
+ GetLevel = DefaultGetLevel,
+ MessageTemplate = DefaultRequestCompletionMessageTemplate
+ };
+ configureOptions?.Invoke(opts);
+
+ if (opts.MessageTemplate == null)
+ throw new ArgumentException($"{nameof(opts.MessageTemplate)} cannot be null.");
+ if (opts.GetLevel == null)
+ throw new ArgumentException($"{nameof(opts.GetLevel)} cannot be null.");
+
+ return app.UseMiddleware(opts);
}
}
-}
+}
\ No newline at end of file