Skip to content

Integrate with LoggerProviderCollection #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 60 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public class Program
```csharp
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseStartup<Startup>()
.UseSerilog() // <-- Add this line
.Build();
}
Expand All @@ -58,28 +58,28 @@ public class Program
**Finally**, clean up by removing the remaining configuration for the default logger:

* Remove calls to `AddLogging()`
* Remove the `"Logging"` section from _appsettings.json_ files (this can be replaced with [Serilog configuration](https://github.com/serilog/serilog-settings-configuration) as shown in [this example](https://github.com/serilog/serilog-aspnetcore/blob/dev/samples/SimpleWebSample/Program.cs), if required)
* Remove the `"Logging"` section from _appsettings.json_ files (this can be replaced with [Serilog configuration](https://github.com/serilog/serilog-settings-configuration) as shown in [the _EarlyInitializationSample_ project](https://github.com/serilog/serilog-aspnetcore/blob/dev/samples/EarlyInitializationSample/Program.cs), if required)
* Remove `ILoggerFactory` parameters and any `Add*()` calls on the logger factory in _Startup.cs_
* Remove `UseApplicationInsights()` (this can be replaced with the [Serilog AI sink](https://github.com/serilog/serilog-sinks-applicationinsights), if required)

That's it! With the level bumped up a little you will see log output like:
That's it! With the level bumped up a little you will see log output resembling:

```
[22:14:44.646 DBG] RouteCollection.RouteAsync
Routes:
Microsoft.AspNet.Mvc.Routing.AttributeRoute
{controller=Home}/{action=Index}/{id?}
Handled? True
Routes:
Microsoft.AspNet.Mvc.Routing.AttributeRoute
{controller=Home}/{action=Index}/{id?}
Handled? True
[22:14:44.647 DBG] RouterMiddleware.Invoke
Handled? True
Handled? True
[22:14:45.706 DBG] /lib/jquery/jquery.js not modified
[22:14:45.706 DBG] /css/site.css not modified
[22:14:45.741 DBG] Handled. Status code: 304 File: /css/site.css
```

Tip: to see Serilog output in the Visual Studio output window when running under IIS, select _ASP.NET Core Web Server_ from the _Show output from_ drop-down list.

A more complete example, showing _appsettings.json_ configuration, can be found in [the sample project here](https://github.com/serilog/serilog-aspnetcore/tree/dev/samples/SimpleWebSample).
A more complete example, showing _appsettings.json_ configuration, can be found in [the sample project here](https://github.com/serilog/serilog-aspnetcore/tree/dev/samples/EarlyInitializationSample).

### Using the package

Expand All @@ -89,21 +89,60 @@ With _Serilog.AspNetCore_ installed and configured, you can write log messages d

### Inline initialization

You can alternatively configure Serilog using a delegate as shown below:
You can alternatively configure Serilog inline, in `BulidWebHost()`, using a delegate as shown below:

```csharp
// dotnet add package Serilog.Settings.Configuration
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
.Enrich.FromLogContext()
.WriteTo.Console())
.ReadFrom.Configuration(hostingContext.Configuration)
.Enrich.FromLogContext()
.WriteTo.Console())
```

This has the advantage of making the `hostingContext`'s `Configuration` object available for configuration of the logger, but at the expense of recording `Exception`s raised earlier in program startup.

If this method is used, `Log.Logger` is assigned implicitly, and closed when the app is shut down.

Note: Configuring Serilog via the `hostingContext`'s `Configuration` object requires that you've installed the _Serilog.Settings.Configuration_ [NuGet package](https://www.nuget.org/packages/Serilog.Settings.Configuration).
A complete example, showing this approach, can be found in [the _InlineIntializationSample_ project](https://github.com/serilog/serilog-aspnetcore/tree/dev/samples/InlineInitializationSample).

### Enabling `Microsoft.Extensions.Logging.ILoggerProvider`s

Serilog sends events to outputs called _sinks_, that implement Serilog's `ILogEventSink` interface, and are added to the logging pipeline using `WriteTo`. _Microsoft.Extensions.Logging_ has a similar concept called _providers_, and these implement `ILoggerProvider`. Providers are what the default logging configuration creates under the hood through methods like `AddConsole()`.

By default, Serilog ignores providers, since there are usually equivalent Serilog sinks available, and these work more efficiently with Serilog's pipeline. If provider support is needed, it can be optionally enabled.

**Using the recommended configuration:**

In the recommended configuration (in which startup exceptions are caught and logged), first create a `LoggerProviderCollection` in a static field in _Program.cs_:

```csharp
// using Serilog.Extensions.Logging;
static readonly LoggerProviderCollection Providers = new LoggerProviderCollection();
```

Next, add `WriteTo.Providers()` to the logger configuration:

```csharp
.WriteTo.Providers(Providers)
```

Finally, pass the provider collection into `UseSerilog()`:

```csharp
.UseSerilog(providers: Providers)
```

Providers registered in _Startup.cs_ with `AddLogging()` will then receive events from Serilog.

**Using iniline initialization:**

If [inline initialization](#inline-initialization) is used, providers can be enabled by adding `writeToProviders: true` to the `UseSerilog()` method call:

```csharp
.UseSerilog(
(hostingContext, loggerConfiguration) => /* snip! */,
writeToProviders: true)
```

### Writing to the Azure Diagnostics Log Stream

Expand All @@ -123,12 +162,12 @@ Then add a file sink to your `LoggerConfiguration`, taking care to set the `shar
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console()
// Add this line:
.WriteTo.File(
@"D:\home\LogFiles\Application\myapp.txt",
fileSizeLimitBytes: 1_000_000,
rollOnFileSizeLimit: true,
shared: true,
flushToDiskInterval: TimeSpan.FromSeconds(1))
// Add this line:
.WriteTo.File(
@"D:\home\LogFiles\Application\myapp.txt",
fileSizeLimitBytes: 1_000_000,
rollOnFileSizeLimit: true,
shared: true,
flushToDiskInterval: TimeSpan.FromSeconds(1))
.CreateLogger();
```
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"sdk": {
"version": "2.0.0"
"version": "2.2.105"
}
}
35 changes: 35 additions & 0 deletions samples/EarlyInitializationSample/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using EarlyInitializationSample.Models;
using Microsoft.Extensions.Logging;

namespace EarlyInitializationSample.Controllers
{
public class HomeController : Controller
{
readonly ILogger<HomeController> _logger;

public HomeController(ILogger<HomeController> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

public IActionResult Index()
{
_logger.LogInformation("Hello, world!");
return View();
}

public IActionResult Privacy()
{
return View();
}

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Serilog.AspNetCore\Serilog.AspNetCore.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="2.4.0" />
</ItemGroup>
Expand Down
9 changes: 9 additions & 0 deletions samples/EarlyInitializationSample/Models/ErrorViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace EarlyInitializationSample.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using System;
using System.IO;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Serilog;

namespace SimpleWebSample
namespace EarlyInitializationSample
{
public class Program
{
Expand All @@ -18,7 +18,6 @@ public class Program

public static int Main(string[] args)
{

Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Enrich.FromLogContext()
Expand Down Expand Up @@ -46,9 +45,9 @@ public static int Main(string[] args)

public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseConfiguration(Configuration)
.UseSerilog()
.Build();
.UseStartup<Startup>()
.UseConfiguration(Configuration)
.UseSerilog()
.Build();
}
}
60 changes: 60 additions & 0 deletions samples/EarlyInitializationSample/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

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<CookiePolicyOptions>(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)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}

app.UseStaticFiles();
app.UseCookiePolicy();

app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
8 changes: 8 additions & 0 deletions samples/EarlyInitializationSample/Views/Home/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@{
ViewData["Title"] = "Home Page";
}

<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
6 changes: 6 additions & 0 deletions samples/EarlyInitializationSample/Views/Home/Privacy.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>
25 changes: 25 additions & 0 deletions samples/EarlyInitializationSample/Views/Shared/Error.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}

<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@using Microsoft.AspNetCore.Http.Features

@{
var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
var showBanner = !consentFeature?.CanTrack ?? false;
var cookieString = consentFeature?.CreateConsentCookie();
}

@if (showBanner)
{
<div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
Use this space to summarize your privacy and cookie use policy. <a asp-area="" asp-controller="Home" asp-action="Privacy">Learn More</a>.
<button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
<span aria-hidden="true">Accept</span>
</button>
</div>
<script>
(function () {
var button = document.querySelector("#cookieConsent button[data-cookie-string]");
button.addEventListener("click", function (event) {
document.cookie = button.dataset.cookieString;
}, false);
})();
</script>
}
Loading