diff --git a/Build.ps1 b/Build.ps1
index 4349906..7c5a85f 100644
--- a/Build.ps1
+++ b/Build.ps1
@@ -1,21 +1,51 @@
+echo "build: Build started"
+
Push-Location $PSScriptRoot
-if(Test-Path .\artifacts) { Remove-Item .\artifacts -Force -Recurse }
+if(Test-Path .\artifacts) {
+ echo "build: Cleaning .\artifacts"
+ Remove-Item .\artifacts -Force -Recurse
+}
-& dotnet restore
+& dotnet restore --no-cache
-$revision = @{ $true = $env:APPVEYOR_BUILD_NUMBER; $false = 1 }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL];
+$branch = @{ $true = $env:APPVEYOR_REPO_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$env:APPVEYOR_REPO_BRANCH -ne $NULL];
+$revision = @{ $true = "{0:00000}" -f [convert]::ToInt32("0" + $env:APPVEYOR_BUILD_NUMBER, 10); $false = "local" }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL];
+$suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)))-$revision"}[$branch -eq "master" -and $revision -ne "local"]
-Push-Location src/Serilog.Extensions.Logging
+echo "build: Version suffix is $suffix"
-& dotnet pack -c Release -o ..\..\.\artifacts --version-suffix=$revision
-if($LASTEXITCODE -ne 0) { exit 1 }
+foreach ($src in ls src/*) {
+ Push-Location $src
-Pop-Location
-Push-Location test/Serilog.Extensions.Logging.Tests
+ echo "build: Packaging project in $src"
-& dotnet test -c Release
-if($LASTEXITCODE -ne 0) { exit 2 }
+ & dotnet pack -c Release -o ..\..\artifacts --version-suffix=$suffix
+ if($LASTEXITCODE -ne 0) { exit 1 }
+
+ Pop-Location
+}
+
+foreach ($test in ls test/*.PerformanceTests) {
+ Push-Location $test
+
+ echo "build: Building performance test project in $test"
+
+ & dotnet build -c Release
+ if($LASTEXITCODE -ne 0) { exit 2 }
+
+ Pop-Location
+}
+
+foreach ($test in ls test/*.Tests) {
+ Push-Location $test
+
+ echo "build: Testing project in $test"
+
+ & dotnet test -c Release
+ if($LASTEXITCODE -ne 0) { exit 3 }
+
+ Pop-Location
+}
-Pop-Location
Pop-Location
diff --git a/CHANGES.md b/CHANGES.md
new file mode 100644
index 0000000..c8e55a8
--- /dev/null
+++ b/CHANGES.md
@@ -0,0 +1,6 @@
+1.1.0
+ * #41 - Provide a `dispose` flag to instruct provider to take ownership of the Serilog logger
+
+1.0.0
+ * Initial version
+
diff --git a/README.md b/README.md
index f5d495e..ebaa3f6 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,8 @@ This package routes ASP.NET log messages through Serilog, so you can get informa
**First**, install the _Serilog.Extensions.Logging_ [NuGet package](https://www.nuget.org/packages/Serilog.Extensions.Logging) into your web or console app. You will need a way to view the log messages - _Serilog.Sinks.Literate_ writes these to the console.
```powershell
-Install-Package Serilog.Extensions.Logging -Pre -DependencyVersion Highest
-Install-Package Serilog.Sinks.Literate -Pre
+Install-Package Serilog.Extensions.Logging -DependencyVersion Highest
+Install-Package Serilog.Sinks.Literate
```
**Next**, in your application's `Startup` method, configure Serilog first:
@@ -38,9 +38,13 @@ call `AddSerilog()` on the provided `loggerFactory`.
```csharp
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
- ILoggerFactory loggerfactory)
+ ILoggerFactory loggerfactory,
+ IApplicationLifetime appLifetime)
{
loggerfactory.AddSerilog();
+
+ // Ensure any buffered events are sent at shutdown
+ appLifetime.ApplicationStopped.Register(Log.CloseAndFlush);
```
That's it! With the level bumped up a little you should see log output like:
diff --git a/appveyor.yml b/appveyor.yml
index 6a39959..19d0d28 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,5 @@
version: '{build}'
+skip_tags: true
image: Visual Studio 2015
configuration: Release
install:
@@ -18,5 +19,11 @@ deploy:
secure: nvZ/z+pMS91b3kG4DgfES5AcmwwGoBYQxr9kp4XiJHj25SAlgdIxFx++1N0lFH2x
skip_symbols: true
on:
- branch: /^(dev|master)$/
-
+ branch: /^(master|dev)$/
+- provider: GitHub
+ auth_token:
+ secure: p4LpVhBKxGS5WqucHxFQ5c7C8cP74kbNB0Z8k9Oxx/PMaDQ1+ibmoexNqVU5ZlmX
+ artifact: /Serilog.*\.nupkg/
+ tag: v$(appveyor_build_version)
+ on:
+ branch: master
diff --git a/samples/WebSample/Controllers/HomeController.cs b/samples/WebSample/Controllers/HomeController.cs
index 0cb5e17..2880e9f 100644
--- a/samples/WebSample/Controllers/HomeController.cs
+++ b/samples/WebSample/Controllers/HomeController.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
+using Serilog;
namespace WebSample.Controllers
{
@@ -10,6 +11,8 @@ public class HomeController : Controller
{
public IActionResult Index()
{
+ Log.Information("Hello from the Index!");
+
return View();
}
@@ -17,6 +20,8 @@ public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
+ Log.Information("This is a handler for {Path}", Request.Path);
+
return View();
}
diff --git a/samples/WebSample/Startup.cs b/samples/WebSample/Startup.cs
index 9d72903..df76f4a 100644
--- a/samples/WebSample/Startup.cs
+++ b/samples/WebSample/Startup.cs
@@ -7,6 +7,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Serilog;
namespace WebSample
{
@@ -14,12 +15,16 @@ public class Startup
{
public Startup(IHostingEnvironment env)
{
- var builder = new ConfigurationBuilder()
+ Configuration = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
- .AddEnvironmentVariables();
- Configuration = builder.Build();
+ .AddEnvironmentVariables()
+ .Build();
+
+ Log.Logger = new LoggerConfiguration()
+ .ReadFrom.Configuration(Configuration)
+ .CreateLogger();
}
public IConfigurationRoot Configuration { get; }
@@ -34,8 +39,8 @@ public void ConfigureServices(IServiceCollection services)
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
- loggerFactory.AddConsole(Configuration.GetSection("Logging"));
- loggerFactory.AddDebug();
+ // Specifying dispose: true closes and flushes the Serilog `Log` class when the app shuts down.
+ loggerFactory.AddSerilog(dispose: true);
if (env.IsDevelopment())
{
diff --git a/samples/WebSample/appsettings.json b/samples/WebSample/appsettings.json
index fa8ce71..02557b3 100644
--- a/samples/WebSample/appsettings.json
+++ b/samples/WebSample/appsettings.json
@@ -1,10 +1,18 @@
{
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
+ "Serilog": {
+ "MinimumLevel": {
"Default": "Debug",
- "System": "Information",
- "Microsoft": "Information"
- }
+ "Override": {
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ },
+ "Enrich": [
+ "FromLogContext"
+ ],
+ "WriteTo": [
+ "Trace",
+ "LiterateConsole"
+ ]
}
}
diff --git a/samples/WebSample/project.json b/samples/WebSample/project.json
index dd01a7f..c9468c7 100644
--- a/samples/WebSample/project.json
+++ b/samples/WebSample/project.json
@@ -19,7 +19,11 @@
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
- "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0"
+ "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
+ "Serilog.Extensions.Logging": { "target": "project" },
+ "Serilog.Settings.Configuration": "2.1.0-dev-00028",
+ "Serilog.Sinks.Trace": "2.0.0",
+ "Serilog.Sinks.Literate": "2.0.0"
},
"tools": {
diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerProvider.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerProvider.cs
index 3f72760..72b010c 100644
--- a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerProvider.cs
+++ b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerProvider.cs
@@ -21,11 +21,20 @@ class SerilogLoggerProvider : ILoggerProvider, ILogEventEnricher
// May be null; if it is, Log.Logger will be lazily used
readonly ILogger _logger;
+ readonly Action _dispose;
- public SerilogLoggerProvider(ILogger logger = null)
+ public SerilogLoggerProvider(ILogger logger = null, bool dispose = false)
{
if (logger != null)
_logger = logger.ForContext(new[] { this });
+
+ if (dispose)
+ {
+ if (logger != null)
+ _dispose = () => (logger as IDisposable)?.Dispose();
+ else
+ _dispose = Log.CloseAndFlush;
+ }
}
public FrameworkLogger CreateLogger(string name)
@@ -77,6 +86,9 @@ public SerilogLoggerScope CurrentScope
}
#endif
- public void Dispose() { }
+ public void Dispose()
+ {
+ _dispose?.Invoke();
+ }
}
}
diff --git a/src/Serilog.Extensions.Logging/SerilogLoggerFactoryExtensions.cs b/src/Serilog.Extensions.Logging/SerilogLoggerFactoryExtensions.cs
index a275721..c2aa06d 100644
--- a/src/Serilog.Extensions.Logging/SerilogLoggerFactoryExtensions.cs
+++ b/src/Serilog.Extensions.Logging/SerilogLoggerFactoryExtensions.cs
@@ -17,14 +17,18 @@ public static class SerilogLoggerFactoryExtensions
///
/// The logger factory to configure.
/// The Serilog logger; if not supplied, the static will be used.
+ /// When true, dispose when the framework disposes the provider. If the
+ /// logger is not specified but is true, the method will be
+ /// called on the static class instead.
/// The logger factory.
public static ILoggerFactory AddSerilog(
this ILoggerFactory factory,
- ILogger logger = null)
+ ILogger logger = null,
+ bool dispose = false)
{
if (factory == null) throw new ArgumentNullException(nameof(factory));
- factory.AddProvider(new SerilogLoggerProvider(logger));
+ factory.AddProvider(new SerilogLoggerProvider(logger, dispose));
return factory;
}
diff --git a/src/Serilog.Extensions.Logging/project.json b/src/Serilog.Extensions.Logging/project.json
index 95a0db4..000eb27 100644
--- a/src/Serilog.Extensions.Logging/project.json
+++ b/src/Serilog.Extensions.Logging/project.json
@@ -1,5 +1,5 @@
{
- "version": "1.0.0",
+ "version": "1.1.0-*",
"description": "Serilog provider for Microsoft.Extensions.Logging",
"authors": [ "Microsoft", "Serilog Contributors" ],
"packOptions": {
diff --git a/test/Serilog.Extensions.Logging.Tests/SerilogLoggerTests.cs b/test/Serilog.Extensions.Logging.Tests/SerilogLoggerTests.cs
index 41ceba5..c50a5da 100644
--- a/test/Serilog.Extensions.Logging.Tests/SerilogLoggerTests.cs
+++ b/test/Serilog.Extensions.Logging.Tests/SerilogLoggerTests.cs
@@ -9,6 +9,7 @@
using System.IO;
using System.Linq;
using Serilog.Debugging;
+using Serilog.Framework.Logging.Tests.Support;
using Xunit;
namespace Serilog.Extensions.Logging.Test
@@ -269,6 +270,24 @@ public void CarriesEventIdIfNonzero()
Assert.Equal(42, id.Value);
}
+ [Fact]
+ public void WhenDisposeIsFalseProvidedLoggerIsNotDisposed()
+ {
+ var logger = new DisposeTrackingLogger();
+ var provider = new SerilogLoggerProvider(logger, false);
+ provider.Dispose();
+ Assert.False(logger.IsDisposed);
+ }
+
+ [Fact]
+ public void WhenDisposeIsTrueProvidedLoggerIsDisposed()
+ {
+ var logger = new DisposeTrackingLogger();
+ var provider = new SerilogLoggerProvider(logger, true);
+ provider.Dispose();
+ Assert.True(logger.IsDisposed);
+ }
+
private class FoodScope : IEnumerable>
{
readonly string _name;
diff --git a/test/Serilog.Extensions.Logging.Tests/Support/DisposeTrackingLogger.cs b/test/Serilog.Extensions.Logging.Tests/Support/DisposeTrackingLogger.cs
new file mode 100644
index 0000000..a967fef
--- /dev/null
+++ b/test/Serilog.Extensions.Logging.Tests/Support/DisposeTrackingLogger.cs
@@ -0,0 +1,354 @@
+using System;
+using System.Collections.Generic;
+using Serilog.Core;
+using Serilog.Events;
+
+namespace Serilog.Framework.Logging.Tests.Support
+{
+ public class DisposeTrackingLogger : ILogger, IDisposable
+ {
+ public bool IsDisposed { get; set; }
+
+ public ILogger ForContext(ILogEventEnricher enricher)
+ {
+ return new LoggerConfiguration().CreateLogger();
+ }
+
+ public ILogger ForContext(IEnumerable enrichers)
+ {
+ return new LoggerConfiguration().CreateLogger();
+ }
+
+ public ILogger ForContext(string propertyName, object value, bool destructureObjects = false)
+ {
+ return new LoggerConfiguration().CreateLogger();
+ }
+
+ public ILogger ForContext()
+ {
+ return new LoggerConfiguration().CreateLogger();
+ }
+
+ public ILogger ForContext(Type source)
+ {
+ return new LoggerConfiguration().CreateLogger();
+ }
+
+ public void Write(LogEvent logEvent)
+ {
+ }
+
+ public void Write(LogEventLevel level, string messageTemplate)
+ {
+ }
+
+ public void Write(LogEventLevel level, string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
+ T2 propertyValue2)
+ {
+ }
+
+ public void Write(LogEventLevel level, string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Write(LogEventLevel level, Exception exception, string messageTemplate)
+ {
+ }
+
+ public void Write(LogEventLevel level, Exception exception, string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Write(LogEventLevel level, Exception exception, string messageTemplate, T0 propertyValue0,
+ T1 propertyValue1)
+ {
+ }
+
+ public void Write(LogEventLevel level, Exception exception, string messageTemplate, T0 propertyValue0,
+ T1 propertyValue1, T2 propertyValue2)
+ {
+ }
+
+ public void Write(LogEventLevel level, Exception exception, string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public bool IsEnabled(LogEventLevel level)
+ {
+ return false;
+ }
+
+ public void Verbose(string messageTemplate)
+ {
+ }
+
+ public void Verbose(string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Verbose(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Verbose(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
+ {
+ }
+
+ public void Verbose(string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Verbose(Exception exception, string messageTemplate)
+ {
+ }
+
+ public void Verbose(Exception exception, string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Verbose(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Verbose(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
+ T2 propertyValue2)
+ {
+ }
+
+ public void Verbose(Exception exception, string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Debug(string messageTemplate)
+ {
+ }
+
+ public void Debug(string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Debug(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Debug(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
+ {
+ }
+
+ public void Debug(string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Debug(Exception exception, string messageTemplate)
+ {
+ }
+
+ public void Debug(Exception exception, string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Debug(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Debug(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
+ T2 propertyValue2)
+ {
+ }
+
+ public void Debug(Exception exception, string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Information(string messageTemplate)
+ {
+ }
+
+ public void Information(string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Information(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Information(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
+ {
+ }
+
+ public void Information(string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Information(Exception exception, string messageTemplate)
+ {
+ }
+
+ public void Information(Exception exception, string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Information(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Information(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
+ T2 propertyValue2)
+ {
+ }
+
+ public void Information(Exception exception, string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Warning(string messageTemplate)
+ {
+ }
+
+ public void Warning(string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Warning(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Warning(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
+ {
+ }
+
+ public void Warning(string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Warning(Exception exception, string messageTemplate)
+ {
+ }
+
+ public void Warning(Exception exception, string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Warning(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Warning(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
+ T2 propertyValue2)
+ {
+ }
+
+ public void Warning(Exception exception, string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Error(string messageTemplate)
+ {
+ }
+
+ public void Error(string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Error(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Error(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
+ {
+ }
+
+ public void Error(string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Error(Exception exception, string messageTemplate)
+ {
+ }
+
+ public void Error(Exception exception, string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Error(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Error(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
+ T2 propertyValue2)
+ {
+ }
+
+ public void Error(Exception exception, string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Fatal(string messageTemplate)
+ {
+ }
+
+ public void Fatal(string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Fatal(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Fatal(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
+ {
+ }
+
+ public void Fatal(string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public void Fatal(Exception exception, string messageTemplate)
+ {
+ }
+
+ public void Fatal(Exception exception, string messageTemplate, T propertyValue)
+ {
+ }
+
+ public void Fatal(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
+ {
+ }
+
+ public void Fatal(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
+ T2 propertyValue2)
+ {
+ }
+
+ public void Fatal(Exception exception, string messageTemplate, params object[] propertyValues)
+ {
+ }
+
+ public bool BindMessageTemplate(string messageTemplate, object[] propertyValues, out MessageTemplate parsedTemplate,
+ out IEnumerable boundProperties)
+ {
+ parsedTemplate = null;
+ boundProperties = null;
+ return false;
+ }
+
+ public bool BindProperty(string propertyName, object value, bool destructureObjects, out LogEventProperty property)
+ {
+ property = null;
+ return false;
+ }
+
+ public void Dispose()
+ {
+ IsDisposed = true;
+ }
+ }
+}