Skip to content

What it is

NLog is a flexible .NET logging platform with rich routing rules, many targets and configuration that can be changed without recompiling.

Targets define destinations, rules route loggers by name and level to targets. Configuration is XML or code, and can reload on change.

Installation

dotnet add package NLog.Web.AspNetCore

Getting started

The smallest useful thing you can do with it, and what each part means.

Configuration and structured logging
<nlog autoReload="true" throwConfigExceptions="true">
  <targets>
    <target name="file" xsi:type="File"
            fileName="logs/${shortdate}.log"
            archiveEvery="Day" maxArchiveFiles="14" />
    <target name="json" xsi:type="File" fileName="logs/app.json">
      <layout xsi:type="JsonLayout" includeEventProperties="true" />
    </target>
  </targets>
  <rules>
    <logger name="Microsoft.*" maxlevel="Info" final="true" />
    <logger name="*" minlevel="Info" writeTo="file,json" />
  </rules>
</nlog>
autoReload means operations can raise the log level on a running process by editing the file. The `final` rule discards framework noise before it reaches any target.

Advanced usage

Where the library earns its place over a simpler alternative.

Scoped properties and async targets
// Named holes, as with Serilog — not interpolation.
_logger.LogInformation("Order {OrderId} shipped to {Customer}",
    order.Id, order.Customer);

using (_logger.BeginScope(new Dictionary<string, object>
{
    ["CorrelationId"] = correlationId,
}))
{
    _logger.LogInformation("processing");   // carries CorrelationId
}

// Wrap slow targets so logging never blocks the request thread.
<target name="asyncFile" xsi:type="AsyncWrapper" queueLimit="5000"
        overflowAction="Discard">
  <target xsi:type="File" fileName="logs/app.log" />
</target>
The AsyncWrapper with an explicit overflow action matters under load: without it, a slow disk turns logging into a bottleneck on the request path.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

No log output at all
Set throwConfigExceptions="true" and internalLogFile to see why the configuration failed to load — a bad target usually fails silently otherwise.
Log entries are lost under load
The async queue overflowed. Raise queueLimit or change overflowAction to Block if losing entries is unacceptable.

Best practices

  • Use message templates with named holes, never string interpolation.
  • Wrap file and network targets in AsyncWrapper so logging does not block requests.
  • Filter framework namespaces with a final rule to cut noise at the source.
  • Call LogManager.Shutdown() on exit so buffered entries are flushed.

Background

Why it exists, and what it was reacting to.

NLog predates structured logging and remains popular where operations teams need to change logging behaviour by editing a configuration file on a running system.