Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use NLog in ASP.NET Core application

I found a CodeProject with an example of how to get this to work, but it doesn't work. The main problem seems to be that the "Microsoft.Framework.Logging.NLog": "1.0.0-*" package doesn't seem to exist in Nuget. I've looked at this StackOverflow question and looked at the GitHub example it references, but it seems to contain the same issue.

I've tried to get it working on my own and the best I've come up with is the following:

public class NLogLogger : ILogger {     public NLogLogger()     {         new WebLoggerConfigurer().ConfigureDefault();     }      public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)     {         // currently need the global:: for LogLevels because our namespace contains NLog in it. Is there a better naming convention we could use instead?         var ll = logLevel == LogLevel.Debug ? global::NLog.LogLevel.Debug                 : logLevel == LogLevel.Verbose ? global::NLog.LogLevel.Trace                 : logLevel == LogLevel.Critical ? global::NLog.LogLevel.Fatal                 : logLevel == LogLevel.Error ? global::NLog.LogLevel.Error                 : logLevel == LogLevel.Information ? global::NLog.LogLevel.Info                 : logLevel == LogLevel.Warning ? global::NLog.LogLevel.Warn                 : global::NLog.LogLevel.Off;          LogManager.GetCurrentClassLogger().Log(ll, formatter(state, exception));     }      public bool IsEnabled(LogLevel logLevel)     {         return true;     }      public IDisposable BeginScopeImpl(object state)     {         return new Disposable(() => { });     } }  public class NLogLoggerProvider : ILoggerProvider {     public void Dispose()     {     }      public ILogger CreateLogger(string categoryName)     {         return new NLogLogger();     } }  public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {     loggerFactory.AddProvider(new NLogLoggerProvider());     .. } 

The implementation of BeginScopeImpl seems to be a hack, but I was unsure how best to implement it.

  1. Does this seem like a valid implementation option?
  2. Is there some better way of implementing BeginScopeImpl?
  3. Is there another way of getting NLog to work with ASP.NET Core?
like image 551
peinearydevelopment Avatar asked Jan 08 '16 14:01

peinearydevelopment


People also ask

Does NLog work with .NET Core?

nuget.org/packages/NLog/… NLog 4.7 has been released! See news post: nlog-project.org/2020/03/28/nlo… While older versions of NLog works well on ASP.NET Core 3, we have optimized the NLog.

Which logging framework is best for .NET Core?

NLog is one of the most popular, and one of the best-performing logging frameworks for . NET. Setting up NLog is fairly simple. Developers can use Nuget to download the dependency, then edit the NLog.


2 Answers

Microsoft.Framework.Logging.NLog has been replaced by NLog.Extensions.Logging on NuGet, which is maintained by the NLog team.

For ASP.NET Core, you need NLog.Web.AspNetCore (which has a dependency on NLog.Extensions.Logging).

How to use:

Setup

NLog needs to be enabled so it will integrate into the DI and log API of ASP.NET Core. This will result that all logs written by externals (e.g. Microsoft) will be also sent to NLog - you could filter that out in the NLog's config (without performance impact).

ASP.NET Core 1

In ASP.NET Core in Configure and optionally ConfigureServices needs to be updated.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {     //add NLog to .NET Core     loggerFactory.AddNLog();      //Enable ASP.NET Core features (NLog.web) - only needed for ASP.NET Core users     app.AddNLogWeb();      //configure nlog.config in your project root.      env.ConfigureNLog("nlog.config");     ...     //you could use LogManager.Configuration from here   public void ConfigureServices(IServiceCollection services) {     // Add framework services.     // e.g. services.AddMvc();      //needed for NLog.Web     services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); } 

ASP.NET Core 2

For ASP.NET Core 2, the setup is different than in ASP.NET Core 1

Set-up NLog in program.cs:

using NLog.Web; using Microsoft.Extensions.Logging;  public static void Main(string[] args) {     // NLog: setup the logger first to catch all errors     var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();     try     {         logger.Debug("init main");         CreateWebHostBuilder(args).Build().Run();      }     catch (Exception ex)     {         //NLog: catch setup errors         logger.Error(ex, "Stopped program because of exception");         throw;     }     finally     {         // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)         NLog.LogManager.Shutdown();     } }  public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>     WebHost.CreateDefaultBuilder(args)         .UseStartup<Startup>()         .ConfigureLogging(logging =>         {             logging.ClearProviders();             logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);         })         .UseNLog();  // NLog: setup NLog for Dependency injection 

ASP.NET Core 3 & 5

There are some small changes compared to ASP.NET Core 2, e.g. there is an IHostBuilder instead of the IWebHostBuilder.

For ASP.NET Core 5 the steps are the same.

Set-up NLog in program.cs:

using System; using NLog.Web; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Hosting;  public static void Main(string[] args) {     var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();     try     {         logger.Debug("init main");         CreateHostBuilder(args).Build().Run();     }     catch (Exception exception)     {         //NLog: catch setup errors         logger.Error(exception, "Stopped program because of exception");         throw;     }     finally     {         // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)         NLog.LogManager.Shutdown();     } }  public static IHostBuilder CreateHostBuilder(string[] args) =>     Host.CreateDefaultBuilder(args)       .ConfigureWebHostDefaults(webBuilder =>       {           webBuilder.UseStartup<Startup>();       })       .ConfigureLogging(logging =>       {           logging.ClearProviders();           logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);       })       .UseNLog();  // NLog: Setup NLog for Dependency injection 

Write logs

Inject an ILogger with the class type as generic argument.

public class HomeController : Controller {     public HomeController(ILogger<HomeController> logger)     {         logger.LogInformation("created homeController");     } 

ASP.NET Core 6

For ASP.NET Core 6 you could configure it without a Startup class. Update Program.cs as follows:

using NLog; using NLog.Web;  var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger(); logger.Debug("init main");  try {     var builder = WebApplication.CreateBuilder(args);      // Add services to the container.     builder.Services.AddControllersWithViews();      // NLog: Setup NLog for Dependency injection     builder.Logging.ClearProviders();     builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);     builder.Host.UseNLog();      var app = builder.Build();      // Configure the HTTP request pipeline.     if (!app.Environment.IsDevelopment())     {         app.UseExceptionHandler("/Home/Error");         // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.         app.UseHsts();     }      app.UseHttpsRedirection();     app.UseStaticFiles();      app.UseRouting();      app.UseAuthorization();      app.MapControllerRoute(         name: "default",         pattern: "{controller=Home}/{action=Index}/{id?}");      app.Run(); } catch (Exception exception) {     // NLog: catch setup errors     logger.Error(exception, "Stopped program because of exception");     throw; } finally {     // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)     NLog.LogManager.Shutdown(); } 

Configure NLog rules

Example on how to configure, log and filter.

Create an nlog.config (for more reading about nlog.config, see docs).

This example will create 2 files, one with all the logs (including Microsoft's) and a file with only your logs.

<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         autoReload="true"         internalLogLevel="Warn"         internalLogFile="c:\temp\internal.txt">       <extensions>         <!--enable NLog.Web for ASP.NET Core-->         <add assembly="NLog.Web.AspNetCore"/>     </extensions>      <!-- define various log targets -->     <targets>         <!-- write logs to file -->         <target xsi:type="File" name="allfile" fileName="c:\temp\nlog-all-${shortdate}.log"                         layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />          <target xsi:type="File" name="ownFile" fileName="c:\temp\nlog-own-${shortdate}.log"                     layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />      </targets>      <rules>         <!--All logs, including from Microsoft-->         <logger name="*" minlevel="Trace" writeTo="allfile" />          <!--Skip Microsoft logs - no writeTo attribute-->         <logger name="Microsoft.*" minlevel="Trace" final="true" />         <logger name="*" minlevel="Trace" writeTo="ownFile" />     </rules> </nlog> 

Publish nlog.config

this isn't a required step for ASP.NET Core 5

Make sure that the nlog.config will be published, e.g in your csproj file:

<ItemGroup>     <Content Update="nlog.config" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup> 

Output

"nlog-own-2018-02-14.log" contains:

2018-02-14 16:27:04.0547|aspnetCoreApplication.Controllers|INFO|created homeController

2018-02-14 16:27:04.0547|aspnetCoreApplication.Controllers|INFO|created homeController

Troubleshoot

Missing debug log messages in ASP.NET Core 2? While the we use SetMinimumLevel in program.cs, also appsettings.json could confluence this.

You could change that as follows:

Change appsettings.json:

{     "Logging": {         "LogLevel": {             "Default": "Trace"         }     } } 

You could also filter Microsoft's logs here, e.g.

{     "Logging": {         "LogLevel": {             "Default": "Trace",             "Microsoft": "Information"         }     } } 

Other issues, see this step plan to find the cause: Logging-troubleshooting in NLog

Cheers,

Julian (NLog)

Edit: updated for NLog.Web.AspNetCore 4.3

Edit 2: Updated for ASP.NET Core 2 and latest recommendations

Edit 3: Updated for ASP.NET Core 3

Edit 4: updated for ASP.NET Core 5

Edit 5: updated for ASP.NET Core 6

like image 155
Julian Avatar answered Sep 22 '22 09:09

Julian


Update to Julian's answer: NLog.Framework.Logging is marked obsolete, use NLog.Extensions.Logging instead (just a package rename, though). Also,env.ConfigureNLog("nlog.config"); works fine only for debugging in Visual Studio (IIS Express). After I've published service to regular IIS on test environment, it failed to start with 500 internal server error. Spent quite a long time to figure out service couldn't find nlog.config at startup anymore. Finally found solution in NLog issues:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationEnvironment appEnv) {     ...     env.ConfigureNLog(Path.Combine(appEnv.ApplicationBasePath, "nlog.config"));     ... } 

Matter is when debugging locally working directory is your project's directory with nlog.config inside, but after publishing to IIS all source files are in %PATH_TO_PUBLISHED_SERVICE%\approot\src\%PROJECT_NAME%\ while working directory is %PATH_TO_PUBLISHED_SERVICE%\.

like image 31
Denis Avatar answered Sep 20 '22 09:09

Denis