Перенаправить весь вывод NLog в Serilog с пользовательской целью

В качестве шага перехода от NLog к Serilog я хочу перенаправить стандартную проводку, лежащую в основе стандартных вызовов NLog. LogManager.GetLogger(name) Соединить любые записи кода с NLog для немедленной пересылки в окружающий Serilog Log.Logger я хочу только один кусок конфигурации, который просто пересылает сообщение, без буферизации Log4net.Appender.Serilog делает для Log4net.

Может кто-нибудь придумать или указать мне канонический фрагмент, который делает это правильно и эффективно, пожалуйста? Требования, которые я могу придумать:

  • Поддерживать уровень, т.е. nlog.Warn должно быть эквивалентно serilog.Warning
  • Serilog может сгенерировать время заново
  • материализация сообщения в приложении, т. е. нет необходимости поддерживать какие-либо свойства, связанные с "сообщением" (LogEvent в терминах серилога)
  • нет буферизации
  • Мне не нужно использовать какую-либо другую цель NLog (то есть изменение / удаление сообщения было бы хорошо)

1 ответ

Решение

Я думаю, что лучший вариант - это пользовательская цель 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 купить мне

Это действительно не нужно при использовании программной конфигурации. Но если у вас есть XML-конфиг, вам нужен регистр.

У меня есть привычка писать цели, которые работают во всех отношениях (регистрация вручную, регистрация по сборке, конфигурация из кода, конфигурация из XML). Я мог понять, что это может сбить с толку.

Другие вопросы по тегам