-
Notifications
You must be signed in to change notification settings - Fork 799
Developing a sink
The following example uses the dotnet
command to create a project.
mkdir SimpleSink
cd SimpleSink
dotnet new console
- Add the Serilog Package from NuGet
dotnet add package serilog
Include the following using
statements. These are used by the sink class and also the configuring Serilog.
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Configuration;
A sink is simply a class that implements the ILogEventSink
interface. The following example renders every message regardless of log level to the console.
public class MySink : ILogEventSink
{
private readonly IFormatProvider _formatProvider;
public MySink(IFormatProvider formatProvider)
{
_formatProvider = formatProvider;
}
public void Emit(LogEvent logEvent)
{
var message = logEvent.RenderMessage(_formatProvider);
Console.WriteLine(DateTimeOffset.Now.ToString() + " " + message);
}
}
A pattern often used when configuring a sink, is to provide an extension method class for the LoggerSinkConfiguration
. The following code illustrates this approach by exposing a MySink
option when configuring Serilog.
public static class MySinkExtensions
{
public static LoggerConfiguration MySink(
this LoggerSinkConfiguration loggerConfiguration,
IFormatProvider formatProvider = null)
{
return loggerConfiguration.Sink(new MySink(formatProvider));
}
}
These extension methods also drive JSON configuration. When configuring from e.g. appsettings.json
, some deployment models require adding the assembly containing the extension method class to the Using
directive:
{
"Serilog": {
"MinimumLevel": "Information",
"Using": [ "Example.SimpleSink" ],
"WriteTo":
[
{ "Name": "MySink" }
]
}
}
As seen in Configuration Basics the new sink can be configured as follows.
var log = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.MySink()
.CreateLogger();
If the sink implements IDisposable
, Serilog will call its Dispose()
method when either Log.CloseAndFlush()
is called (when using the static Log
class), or the Logger
writing to the sink is disposed directly.
If a sink cannot accept/successfully process an event, it can (and should) throw an exception from Emit()
to notify Serilog of this. Serilog will suppress the exception and write a standard diagnostic message to SelfLog
, unless the sink is configured explicitly for auditing.
Sinks can additionally write diagnostic messages to SelfLog
, however this should be done sparingly to avoid adverse performance impact.
Sinks must be completely thread-safe once constructed, and accept calls to Emit()
on any thread. Serilog will invoke Emit()
concurrently.
Below is the full example code as a console app.
using System;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Configuration;
namespace SimpleSink
{
class Program
{
static void Main(string[] args)
{
var log = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.MySink()
.CreateLogger();
var position = new { Latitude = 25, Longitude = 134 };
var elapsedMs = 34;
log.Information("Processed {@Position} in {Elapsed:000} ms.", position, elapsedMs);
}
}
public class MySink : ILogEventSink
{
private readonly IFormatProvider _formatProvider;
public MySink(IFormatProvider formatProvider)
{
_formatProvider = formatProvider;
}
public void Emit(LogEvent logEvent)
{
var message = logEvent.RenderMessage(_formatProvider);
Console.WriteLine(DateTimeOffset.Now.ToString() + " " + message);
}
}
public static class MySinkExtensions
{
public static LoggerConfiguration MySink(
this LoggerSinkConfiguration loggerConfiguration,
IFormatProvider formatProvider = null)
{
return loggerConfiguration.Sink(new MySink(formatProvider));
}
}
}
Example Output
17/01/2017 3:10:26 PM +10:00 Processed { Latitude: 25, Longitude: 134 } in 034 ms.