Configure NLog in .NET Core Application

NLog is a C# library used for logging. It is highly configurable, used by many projects. It supports by default various destinations for logs.

I recommend using the NLog or Serilog. These two libraries are very similar and they have the most number of destinations already implemented.

NLog configuration

The configuration is built on three major properties:

  1. Target property sets where do you want to store the logs. NLog currently has 84 options for the destination of your logs: file, mail, different databases, Azure products like Azure Insights, Table Storage, or Azure Hub Event.

    For the implementation of your own custom targets, you must inheritance TargetWithLayout class.

  2. Layout specifies the format of a log: plain text, JSON, XML, or CSV.

  3. Layout renderers give you contextual data. For instance, there are ASP.NET renderers that give you information about the HTTP request, IP, session, status code.

    You will need different renderers to easily find what was the cause of the error. The date renderers are important, to see when a log happened.

    You can use the renderers, by using the markers and configuring your own logging template. You can find the markers at this address.

    An example of a log template looks like this:

    ${longdate}|${aspnet-traceidentifier}|${uppercase:${level}}|${threadid}|${logger}|${message} ${exception:format=ToString}|${aspnet-request-method}|${aspnet-request-url}|${aspnet-mvc-action}|${aspnet-request-posted-body}

    Most of the tags are pretty self-explanatory. We include information like the time, the log level, the stack trace, and details about the request.

NLog Logging Levels

The library has 6 levels that can be used to filter and segregate logs. 

  1. Trace – Use to see the trail of the execution
  2. Debug – Used for debugging reasons
  3. Info – Inform about execution steps
  4. Warn  – Something happened, but the execution continues
  5. Error  – Something bad happened, the execution doesn’t continue
  6. Fatal – The application doesn’t work (e.g. Out of memory)

One cool feature is that you can skip some logs for different targets. For example, for one of my projects, I save all the logs in files and write in the database only the exceptions.

Implement NLog in ASP.NET Core

  1. Install the Nuget packages.

    Install-Package NLog.Web.AspNetCore
    Install-Package NLog
  2. Create the nlog.config file at the root of your project

    <?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="Info"
          internalLogFile="${basedir}\internal-nlog.txt">
    
      <!-- enable asp.net core layout renderers -->
      <extensions>
        <add assembly="NLog.Web.AspNetCore"/>
      </extensions>
    
      <targets>
        <target xsi:type="AsyncWrapper" name="AllAsyncWrapper" queueLimit="10000" batchSize="1000">
          <target xsi:type="File"
                  name="allfile"
                  fileName="${basedir}\nlog-all-${shortdate}-${environment:ASPNETCORE_ENVIRONMENT}.log"
                  archiveFileName="${basedir}\archives\nlog-all-${shortdate}-${environment:ASPNETCORE_ENVIRONMENT}.archive-{#}.zip"
                  archiveEvery="Day"
                  maxArchiveDays="7"
                  archiveNumbering="DateAndSequence"
                  enableArchiveFileCompression="True"
                  layout="${longdate}|${aspnet-traceidentifier}|${uppercase:${level}}|${threadid}|${logger}|${message} ${exception:format=ToString}|${aspnet-request-method}|${aspnet-request-url}|${aspnet-mvc-action}|${aspnet-request-posted-body}" />
        </target>
      </targets>
    
      <!-- rules to map from logger name to target -->
      <rules>
        <logger name="*" minlevel="Error" writeTo="AllAsyncWrapper" />
      </rules>
    </nlog>

    The above code only logs code from the Error level above. So, the info logs are not captured.

    You can use multiple targets, with different rules. 

    It is important to copy the nlog.config file to the output directory.

    NLog - Copy To Output Directory
  3. Change Program.cs file
    public static class Program
    {
        public static async Task Main(string[] args)
        {
            var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
            try
            {
                logger.Debug("init main");
    
                var webhost = CreateWebHostBuilder(args).Build();
                await webhost.RunAsync();
            }
            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 CreateWebHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.SetMinimumLevel(LogLevel.Trace);
        })
            .UseNLog();  // NLog: Setup NLog for Dependency injection
    }

     

  4. Remove the logging object from appsettings.json. The alternative is to adjust to your specific needs.
    // remove or adapt
     "Logging": { 
        "LogLevel": {
          "Default": "Information",
          "Hangfire": "Information"
        }
      }
  5. Use the logger – you can inject the interface ILogger into your controllers and log custom messages.
    public class PaymentRepo : IPaymentRepo
       {
           private readonly ILogger _logger;
    
           public PaymentRepo(ILogger<PaymentRepo> logger)
           {           
               _logger = logger;
           }
    
    
    
           public async Task<(string, List<Cashout>)> GetPayments(int userId)
           {
               _logger.Log(nameof(GetPayments));
               
               try
               {
               //call the db to get the payments
               }
               catch (Exception ex)
               {
                
                   _logger.LogError(ex, ex.Message);
               }
    
               return r;
           }
       }
  6. Check the log file that was generated by NLog.

NLog Logging File

You can find the source code on Github.

Leave a Comment