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

时间:2018-03-31 20:59:27

标签: nlog target porting serilog sink

作为从NLog切换到Serilog的一个步骤,我想重定向NLog LogManager.GetLogger(name)标准调用的标准接线,以桥接任何记录到NLog的代码,立即转发到环境Serilog Log.Logger - 即我想只是一个简单转发消息的配置,而不像Log4net.Appender.Serilog那样为Log4net进行缓冲。

任何人都可以编造或指向我正确而有效地执行此操作的规范片段吗?我能想到的要求:

  • 维持关卡,即nlog.Warn应相当于serilog.Warning
  • Serilog可以重新产生时间
  • 在appender中实现消息 - 即,不需要维护与'message'相关的任何属性(Serilog术语中的LogEvent
  • no buffering
  • 我不需要使用任何其他NLog目标(即改变/删除该消息就可以了)

1 个答案:

答案 0 :(得分:5)

我认为最好的选择确实是自定义NLog目标。像这样:(C#)

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.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的调用

    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;
    }

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

  

这样做的最佳方式,不会引起任何可避免的冲击力等。

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

  

TargetAttribute买了什么?

在这种情况下你不需要它。注册完整程序集时使用TargetAttribute,但由于我们手动注册,因此不需要Register。我认为这是最好的做法,但你可以把它留下来。

  

from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutExceptio options = webdriver.ChromeOptions() options.add_argument("--user-data- dir=C:/Users/MyPC/AppData/Local/Google/Chrome/User Data") driver = webdriver.Chrome(chrome_options=options) driver.get("page to be loaded") 还给我买什么

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

我习惯于编写各种方式的目标(手动注册,按汇编注册,从代码配置,从XML配置)。我能理解这可能令人困惑。