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