我正在使用基于代码的 Serilog 配置(不是应用程序设置)。我想在运行时切换接收器;特别是 Seq,还有其他的。
我知道
WriteTo.Conditional
功能:
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))
);
但是该代码位于组合根中(即它在应用程序启动期间运行)。我需要稍后切换水槽。
我可能需要解决一些可以做出切换决定的服务。但是我如何在运行时将其连接到上面的配置代码?我找不到此类功能的挂钩。
(请注意,切换到应用程序设置方法是不可行的。)
我找到了一个解决方案解决方法,基于这个。
添加一个封装类型
LoggingLevelSwitch
:
public class SinkSwitch
{
private readonly LoggingLevelSwitch _switch;
private readonly LogEventLevel _levelOff = (LogEventLevel)int.MaxValue;
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 void Toggle()
{
_switch.MinimumLevel = _switch.MinimumLevel == _levelOff
? _level
: _levelOff;
}
public void Change(LogEventLevel level)
{
if (!Enum.IsDefined(level)) throw new ArgumentOutOfRangeException(nameof(level));
_level = level;
_switch.MinimumLevel = level;
}
}
在启动过程中,在配置 Serilog 之前,创建开关并将其存储为单例:
var sinkSwitch = new SinkSwitch(LogEventLevel.Information);
services.AddSingleton(sinkSwitch);
然后配置Serilog:
services.AddSerilog((services, config) => config
// ...
.WriteTo.Console(levelSwitch:sinkSwitch.Switch)
.WriteTo.Seq(SEQ_URL, controlLevelSwitch:sinkSwitch.Switch)
);
备注:
_levelOff
)这感觉就像一个黑客,因为如果库发生变化(以验证枚举值,就像我上面所做的那样),那么这种方法将会失败。 如果您有更好的解决方案,请发布,我会接受。