Microsoft.Extensions.Logging Vs. NLog
Asked Answered
A

2

31

I see a lot of posts mentioning usage of Microsoft.Extensions.Logging together with NLog.

I'd like to better understand what Microsoft.Extensions.Logging is used for?

And specifically why is it needed or what's the benefit of using it together with NLog?

Alkanet answered 2/10, 2019 at 20:41 Comment(1)
Microsoft AspNetCore-engine will only log to Microsoft-Extension-Logging (MEL). If you want to monitor / diagnose issue with that engine, and like NLog. Then you can register NLog to become a MEL-LoggingProvider. Also Microsoft Dependency-Injection will by default automatically provide its own MEL-ILogger-instances as constructor parameters.Oriana
K
29

With NLog you could do:

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

That works for all platforms and all frameworks.

Microsoft.Extensions.Logging

With .NET Core, Microsoft introduced the ILogger abstraction from Microsoft.Extensions.Logging. You could use that logging abstraction in your project and integrate it with NLog.

For example in ASP.NET Core you could inject Microsoft.Extensions.Logging.ILogger<HomeController> and that could send the logs to NLog. (see 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();
    }

Packages

For NLog and Microsoft.Extensions.Logging there are the following packages:

Comparison

NLog Pros

Pros of using NLog directly

  • Best performance
  • More options with the logger API, e.g. Logger.WithProperty(..)
  • Works in all platforms
  • No Dependency Injection needed which saves complexity.

Pros Microsoft.Extensions.Logging

Pros of using NLog via Microsoft.Extensions.Logging:

  • Fully integrated with ASP.NET Core, e.g. Microsoft also writes to the logger API and that will be also captured (and possible filtered) by NLog
  • Writing to the logging abstraction will make your code log-library independent.
  • Works well with .NET Core Dependency injection
  • new: You could configure NLog with appsettings.json - so with JSON instead of XML

Update: added - Using NLog with appsettings.json

Keiko answered 2/10, 2019 at 23:22 Comment(4)
Another pro of NLog: API is concise and easier to write. e.g. log.Info(...) instead of logger.LogInformation(...). Arguably, you can create extension methods to overcome that, but it's nice to have it out-of-the-box.Isolationism
@SedatKapanoglu in my opinion, logger.LogInformation(...) seems more clear than log.Info(...) when LogInformation means yep it's gonna log information, but when i see Info method it confusing me. is it gonna show me info or send it somewhere?Biddy
@TimurVafin Yes, but sometimes, it can be preferable to have an idiomatic API over a verbose one. Once you get used to it, it's self-consistent, it doesn't surprise you, and you become more productive with it. A perfect example would be Linq extension methods like Where, Select which are not descriptive at all by themselves, but in the context of Linq, they make perfect sense. I think this is also such an example in the context of logging.Isolationism
I guess its personal which is better for the method names. That's why it isn't listed in the answer.Keiko
A
1

Microsoft.Extensions.Logging is used for dependency injection, which is handy for unit testing: you can implement a logger with a LoggedText property to support Assert.IsTrue(_logger.LoggedText.Contains("expected value")). The following example illustrates such a class that implements Microsoft.Extensions.Logging.ILogger<T> and also (for fun) uses Julian's suggestion of sending the message to NLog as well:

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(); }
           
    }
}
Affiche answered 13/5, 2021 at 0:0 Comment(1)
This works against the idea that the Logger should be agnostic to the output format. Think using NLog.Extensions.Logging with LoggerFactory, and then configure a NLog target with JsonLayout would be a better choice.Oriana

© 2022 - 2024 — McMap. All rights reserved.