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

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

  • 保持级别,即nlog.Warn应该等效于serilog.Warning
  • Serilog可以重新生成时间
  • 是可以的
  • 在附加器中实现消息-即,无需维护与“消息”(Serilog术语中的LogEvent)相关联的任何属性
  • 没有缓冲
  • 我不需要使用任何其他NLog目标(即,更改/删除消息就可以了)
  • 最佳答案

    我认为最好的选择确实是自定义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.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的调用

        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,但由于我们是手动注册的,因此不需要它。我认为这是最佳做法,但您可以忽略它。



    当以编程方式使用配置时,确实不需要这样做。但是,如果您具有XML配置,则需要注册。

    我习惯于编写可以以所有方式工作的目标(手动注册,按程序集注册,从代码配置,从XML配置)。我可以理解,这可能会造成混淆。

    F#端口:

    module SerilogHelpers =
    
        let private mapLevel = function
            | x when x = NLog.LogLevel.Info -> LogEventLevel.Information
            | x when x = NLog.LogLevel.Off || x = NLog.LogLevel.Trace -> LogEventLevel.Verbose
            | x when x = NLog.LogLevel.Debug -> LogEventLevel.Debug
            | x when x = NLog.LogLevel.Warn -> LogEventLevel.Warning
            | x when x = NLog.LogLevel.Error ->  LogEventLevel.Error
            | _ -> LogEventLevel.Fatal
    
        // via https://stackoverflow.com/a/49639001/11635
        [<NLog.Targets.Target("SerilogTarget")>]
        type SerilogTarget() =
            inherit NLog.Targets.Target()
    
            static member InitializeAsGlobalTarget() =
                // sic: blindly overwrite the forwarding rules every time
                // necessary as Azure Startup establishes a different config as a bootstrapping step
                // see: LogModule.To.target("rollingFile", create, "*", LogLevel.Trace)
                let cfg, target = NLog.Config.LoggingConfiguration(), SerilogTarget()
                cfg.AddTarget("SerilogTarget", target)
                cfg.LoggingRules.Add(NLog.Config.LoggingRule("*", NLog.LogLevel.Trace, target))
                // NB assignment must happen last; rules get ingested upon assignment
                NLog.LogManager.Configuration <- cfg
    
            override __.Write(logEvent : NLog.LogEventInfo) =
                let log = Log.ForContext(Serilog.Core.Constants.SourceContextPropertyName, logEvent.LoggerName)
                match logEvent.Parameters with
                | xs when isNull xs || xs.Length = 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)
                    let template = MessageTemplate [| Serilog.Parsing.TextToken(logEvent.FormattedMessage) |]
                    log.Write(new LogEvent(DateTimeOffset.Now, mapLevel logEvent.Level, logEvent.Exception, template, Seq.empty<LogEventProperty>))
                | _ ->
                    // Risk: tunneling an NLog format and assuming it will Just Work as a Serilog format
                    log.Write(mapLevel logEvent.Level, logEvent.Exception, logEvent.Message, logEvent.Parameters)
    

    关于nlog - 使用自定义目标将所有NLog输出重定向到Serilog,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49592351/

    10-12 12:50
    查看更多