gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 03:58:52 29 4
gpt4 key购买 nike

作为从 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

the optimal way to do this without inducing any avoidable perf impact etc.

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

what does the TargetAttribute buy me ?

在这种情况下你不需要它。 TargetAttribute在注册完整程序集时使用,但因为我们手动注册,所以不需要它。我认为这是最佳实践,但您可以忽略它。

Also what does the Register buy me

当使用编程方式配置时,这确实是不需要的。但如果您有 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/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com