Microsoft.Extensions.Logging 比。日志

Microsoft.Extensions.Logging Vs. NLog

我看到很多帖子提到 Microsoft.Extensions.Logging 与 NLog 一起使用。

我想更好地了解 Microsoft.Extensions.Logging 的用途?

具体为什么需要它或者将它与 NLog 一起使用有什么好处?

使用 NLog 你可以做:

var logger = NLog.LogManager.GetCurrentClassLogger();
logger.Info("Hello {Name}", "Earth");

适用于所有平台和所有框架。

Microsoft.Extensions.Logging

对于 .NET Core,Microsoft 从 Microsoft.Extensions.Logging 引入了 ILogger abstraction。您可以在您的项目中使用该日志记录抽象并将其与 NLog 集成。

例如,在 ASP.NET Core 中,您可以注入 Microsoft.Extensions.Logging.ILogger<HomeController> 并且可以将日志发送到 NLog。 (参见 Getting started with ASP.NET Core 2 · NLog/NLog Wiki

using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public IActionResult Index()
    {
        _logger.LogInformation("Index page says hello {Name}", "Universe");
        return View();
    }

套餐

对于 NLog 和 Microsoft.Extensions.Logging,有以下软件包:

比较

NLog 优点

直接使用 NLog 的优点

  • 最佳表现
  • 记录器的更多选项 API,例如Logger.WithProperty(..)
  • 适用于所有平台
  • 无需依赖注入,从而降低了复杂性。

优点Microsoft.Extensions.Logging

通过 Microsoft.Extensions.Logging 使用 NLog 的优点:

  • 与 ASP.NET 核心完全集成,例如Microsoft 还写入记录器 API 并且 NLog
  • 也会捕获(并可能过滤)
  • 写入日志抽象将使您的代码日志库独立。
  • 与 .NET Core 依赖注入配合良好
  • new:你可以 configure NLog with appsettings.json - 所以用 JSON 而不是 XML

更新:添加 - Using NLog with appsettings.json

Microsoft.Extensions.Logging 用于依赖注入,这对单元测试很方便:你可以用 LoggedText 属性 实现一个记录器来支持 Assert.IsTrue(_logger.LoggedText.Contains("expected value"))。下面的示例说明了这样一个 class 实现 Microsoft.Extensions.Logging.ILogger<T> 并且(为了好玩)也使用 Julian 的建议将消息​​发送到 NLog:

using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
    
namespace MyDomain.Tests
{
   internal class WrappedNLogger<T> : ILogger<T>
    {
       private StringBuilder _sb = new StringBuilder(); //Support Assert.IsTrue(_logger.LoggedText == "expected value")
        private NLog.Logger _nlog = NLog.LogManager.GetCurrentClassLogger(); //support use of NLog

        public IDisposable BeginScope<TState>(TState state) => default;

        public bool IsEnabled(LogLevel logLevel) => true;

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            var jsonLine = JsonConvert.SerializeObject(new
            {
                timestamp = DateTime.Now.ToLongTimeString(),
                logLevel,
                eventId,
                parameters = (state as IEnumerable<KeyValuePair<string, object>>)?.ToDictionary(i => i.Key, i => i.Value),
                message = formatter(state, exception),
                exception = exception?.GetType().Name
            });

            _sb.AppendLine(jsonLine);
            NLog.LogLevel nloglevel = logLevel == LogLevel.Debug ? NLog.LogLevel.Debug
                                    : logLevel == LogLevel.Information ? NLog.LogLevel.Info
                                    : logLevel == LogLevel.Warning ? NLog.LogLevel.Warn
                                    : logLevel == LogLevel.Error ? NLog.LogLevel.Error
                                    : logLevel == LogLevel.Critical ? NLog.LogLevel.Fatal : NLog.LogLevel.Trace;
            _nlog.Log(nloglevel, jsonLine);
        }

        public string LoggedText { get => _sb.ToString(); }
           
    }
}