使用自定义目标将所有 NLog 输出重定向到 Serilog

问题描述 投票:0回答:1

作为从 NLog 切换到 Serilog 的一步,我想重定向 NLog

LogManager.GetLogger(name)
标准调用的标准接线,以桥接任何代码日志记录到 NLog,以立即转发到环境 Serilog
Log.Logger
- 即我只想一个只是转发消息的配置,无需像 Log4net 那样进行缓冲。
任何人都可以编造或向我指出一个可以正确有效地执行此操作的规范片段吗?我能想到的要求:

保持水平,即

Log4net.Appender.Serilog

应等于
    NLog.Warn
  • Serilog重新生成时间就可以了
    在附加程序中具体化消息 - 即,无需维护与“消息”相关的任何属性(Serilog 术语中的 
  • serilog.Warning
  • 无缓冲
    我不需要使用任何其他 NLog 目标(即改变/删除消息就可以了)
  • 我认为最好的选择确实是自定义 NLog 目标。像这样的东西:(C#)
nlog target porting serilog sink
1个回答
11
投票

在您的

using NLog; using NLog.Targets; using Serilog; using Serilog.Events; namespace MyNamespace { [Target("SerilogTarget")] public sealed class SerilogTarget : TargetWithLayout { protected override void Write(LogEventInfo logEvent) { var log = Log.ForContext(Serilog.Core.Constants.SourceContextPropertyName, logEvent.LoggerName); var logEventLevel = ConvertLevel(logEvent.Level); if ((logEvent.Parameters?.Length ?? 0) == 0) { // NLog treats a single string as a verbatim string; Serilog treats it as a String.Format format and hence collapses doubled braces // This is the most direct way to emit this without it being re-processed by Serilog (via @nblumhardt) var template = new Serilog.Events.MessageTemplate(new[] { new Serilog.Parsing.TextToken(logEvent.FormattedMessage) }); log.Write(new Serilog.Events.LogEvent(DateTimeOffset.Now, logEventLevel, logEvent.Exception, template, Enumerable.Empty<Serilog.Events.LogEventProperty>())); } else // Risk: tunneling an NLog format and assuming it will Just Work as a Serilog format #pragma warning disable Serilog004 // Constant MessageTemplate verifier log.Write(logEventLevel, logEvent.Exception, logEvent.Message, logEvent.Parameters); #pragma warning restore Serilog004 } static Serilog.Events.LogEventLevel ConvertLevel(LogLevel logEventLevel) { if (logEventLevel == LogLevel.Info) return Serilog.Events.LogEventLevel.Information; else if (logEventLevel == LogLevel.Trace) return Serilog.Events.LogEventLevel.Verbose; else if (logEventLevel == LogLevel.Debug) return Serilog.Events.LogEventLevel.Debug; else if (logEventLevel == LogLevel.Warn) return Serilog.Events.LogEventLevel.Warning; else if (logEventLevel == LogLevel.Error) return Serilog.Events.LogEventLevel.Error; return Serilog.Events.LogEventLevel.Fatal; } } }
main()

中注册:


app_start

在进行任何记录之前,需要连接

// Register so it can be used by config file parsing etc Target.Register<MyNamespace.SerilogTarget>("SerilogTarget");
,以便
Target

实际上可以触发对

LogManager.GetLogger()
的调用

SerilogTarget.Write

另请参阅:
https://github.com/nlog/nlog/wiki/How-to-write-a-custom-target

在不引起任何可避免的性能影响等的情况下执行此操作的最佳方法。

这是NLog中的最佳方式,对NLog站点没有性能影响。

public static void ReplaceAllNLogTargetsWithSingleSerilogForwarder() { // sic: blindly overwrite the forwarding rules every time var target = new SerilogTarget(); var cfg = new NLog.Config.LoggingConfiguration(); cfg.AddTarget(nameof(SerilogTarget), target); cfg.LoggingRules.Add(new NLog.Config.LoggingRule("*", LogLevel.Trace, target)); // NB assignment must happen last; rules get ingested upon assignment LogManager.Configuration = cfg; }

给我买了什么?

在这种情况下你不需要它。注册完整程序集时使用 
TargetAttribute

,但因为我们手动注册,所以不需要它。我认为这是最佳实践,但您可以忽略它。

还有
TargetAttribute

给我买了什么

使用编程配置时确实不需要这样做。但如果你有 XML 配置,你需要注册。

我习惯编写以各种方式工作的目标(手动注册、通过程序集注册、从代码配置、从 XML 配置)。我可以理解这可能会令人困惑。

F#端口:

Register

© www.soinside.com 2019 - 2024. All rights reserved.