I'm using code-based Serilog config (not appsettings). I want to toggle a sink at runtime; specifically Seq, but others too.
I know of the WriteTo.Conditional
feature:
var isFooEnabled = true;
var isSeqEnabled = true;
services.AddSerilog((services, config) => config
// ...
.WriteTo.Console()
.WriteTo.Conditional(x => isFooEnabled, x => x.Foo())
.WriteTo.Conditional(x => isSeqEnabled, x => x.Seq(SEQ_URL))
);
But that code is located in the composition root (i.e. it's run during app start). I need to toggle a sink much later.
I'd probably need to resolve some service which can make the toggling decision. But how would I connect that to the above config code, at runtime? I couldn't find a hook for such functionality.
(Please note that switching to the appsettings approach is not feasible.)
I found a solution, based on this and this.
Add a type that encapsulates LoggingLevelSwitch
:
public class SinkSwitch
{
private readonly LoggingLevelSwitch _switch;
private LogEventLevel _level;
public SinkSwitch(LogEventLevel level)
{
if (!Enum.IsDefined(level)) throw new ArgumentOutOfRangeException(nameof(level));
_level = level;
_switch = new LoggingLevelSwitch(level);
}
public LoggingLevelSwitch Switch => _switch;
public bool IsEnabled => _switch.MinimumLevel != LevelAlias.Off;
public void Toggle()
{
_switch.MinimumLevel = _switch.MinimumLevel == LevelAlias.Off
? _level
: LevelAlias.Off;
}
public void Change(LogEventLevel level)
{
if (!Enum.IsDefined(level)) throw new ArgumentOutOfRangeException(nameof(level));
_level = level;
_switch.MinimumLevel = level;
}
}
During startup, before configuring Serilog, create the switch and store it as a singleton:
var sinkSwitch = new SinkSwitch(LogEventLevel.Information);
services.AddSingleton(sinkSwitch);
Then configure Serilog:
services.AddSerilog((services, config) => config
// ...
.WriteTo.Console(levelSwitch:sinkSwitch.Switch)
.WriteTo.Seq(SEQ_URL, controlLevelSwitch:sinkSwitch.Switch)
);
Notes:
LevelAlias.Off
SinkSwitch
from consumer code (e.g. a controller or some service) and invoke switch.Toggle()