IDOC.Logs.Nlog 1.5.0

dotnet add package IDOC.Logs.Nlog --version 1.5.0
                    
NuGet\Install-Package IDOC.Logs.Nlog -Version 1.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="IDOC.Logs.Nlog" Version="1.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="IDOC.Logs.Nlog" Version="1.5.0" />
                    
Directory.Packages.props
<PackageReference Include="IDOC.Logs.Nlog" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add IDOC.Logs.Nlog --version 1.5.0
                    
#r "nuget: IDOC.Logs.Nlog, 1.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package IDOC.Logs.Nlog@1.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=IDOC.Logs.Nlog&version=1.5.0
                    
Install as a Cake Addin
#tool nuget:?package=IDOC.Logs.Nlog&version=1.5.0
                    
Install as a Cake Tool

IDOC.Logs.Nlog

NLog target that sends log entries over UDP encrypted with DTLS 1.2 to a centralizing log server.

Each log entry is serialized as UTF-8 JSON and transmitted via a persistent DTLS session. If the connection fails, the target backs off for 30 seconds before retrying — log events emitted during the cooldown are silently dropped to avoid blocking the application.

Installation

dotnet add package IDOC.Logs.Nlog

Configuration

NLog.config

<?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">

  <extensions>
    <add assembly="IDOC.Logs.Nlog" />
  </extensions>

  <targets>
    <target xsi:type="UdpTls"
            name="centralisateur"
            address="192.168.1.100"
            port="5140"
            application="MyApp"
            version="1.2.0"
            niveauEnvoi="Info" />
  </targets>

  <rules>
    
    <logger name="*" minlevel="Trace" writeTo="centralisateur" />
  </rules>

</nlog>

Programmatic (NLog fluent API)

var config = new NLog.Config.LoggingConfiguration();

var target = new IDOC.Logs.NLog.UdpTlsTarget
{
    Name        = "centralisateur",
    Address     = "192.168.1.100",
    Port        = 5140,
    Application = "MyApp",
    // Version is auto-detected from the entry assembly when omitted
};

config.AddTarget(target);
config.AddRuleForAllLevels(target);
NLog.LogManager.Configuration = config;

Target properties

Property Type Default Description
Address string "127.0.0.1" IP address or hostname of the log server
Port int 5140 UDP port of the log server
Application string? null Application name injected into each log entry
Version string? auto Application version. If omitted, detected automatically from the entry assembly (Assembly.GetEntryAssembly().GetName().Version).
NiveauEnvoi string "Info" Minimum level actually transmitted to the server. Events below this level only feed the breadcrumb buffer. Route the NLog rule with minlevel="Trace" to get full breadcrumbs. Since 1.5.0 this is the local default: the server may override it per application at runtime (see Server-driven emission level); if it does, the override wins until it expires, then the value here applies again.
KeepAliveSeconds int 60 Heartbeat interval in seconds (0 disables). Keeps the UDP/NAT mapping alive and detects zombie sessions: the server echoes each heartbeat; after 2 heartbeats without echo (server restarted), the session is renewed. See Connection behaviour.
TailleMaxDatagramme int 1200 Max datagram payload (bytes), kept under the ~1400 MTU so IP never fragments (fragmented UDP is often silently dropped). Larger payloads are split into up to 4 chunks reassembled by the server; beyond that the payload is degraded (fewer/truncated breadcrumbs, truncated message) so a log always gets through.
ScopeProperties string "Cid,RequestPath" Comma-separated whitelist of NLog scope properties to keep. Cid is promoted to a dedicated payload field; the others go into Contexte. Properties outside the list (ASP.NET Core noise: ConnectionId, RequestId, ActionId…) are dropped. "*" keeps everything.

Connection behaviour and keepalive

The DTLS session is opened lazily on the first log write and reused for subsequent logs.

Behind a NAT with a short UDP idle timeout — typically Azure Container Instances, where an expired outbound UDP mapping is not reliably re-established — a session left idle would be silently torn down, and generating traffic afterwards does not bring it back. To prevent this, a background timer sends a small heartbeat on the open session every KeepAliveSeconds, so the mapping is refreshed regularly and never expires. The heartbeat carries a marker (IDOC-KEEPALIVE) that the server recognises and drops — it creates no log entry. This requires a server that understands the marker (IDOC.Logs.Serveur; older servers would just log it as an invalid payload).

Choose KeepAliveSeconds below the NAT's UDP idle timeout (60–120 s is a safe range for most environments). If a heartbeat or a log send fails, the session is closed and a 30 s cooldown applies before the next attempt; events emitted during the cooldown are dropped without blocking the caller. Certificate validation is intentionally skipped — the target targets internal networks with a self-signed server certificate; DTLS encryption still protects the transport.

Server-driven emission level

Since 1.5.0, the heartbeat carries the application name (IDOC-KEEPALIVE|<application>) and the server replies with the emission level it wants that application to use (IDOC-KEEPALIVE|<level>). When a level is returned, it overrides NiveauEnvoi at runtime — letting an operator temporarily lower an application to Trace for a diagnostic window, then restore it centrally, without redeploying. The change takes effect within one heartbeat interval (KeepAliveSeconds).

The local NiveauEnvoi is always the fallback: an empty reply (no override configured, or the override expired) or an older server that echoes the bare heartbeat both leave the local value in force. A malformed/unknown level is ignored. Set the override and its optional expiry per application in the log server admin (or via PATCH /api/applicationsautorisees/{nom}/niveau).

1.5.0 requires an up-to-date IDOC.Logs.Serveur (heartbeat echo carrying the level). Deploy the server first; a 1.5.0 client against an older server keeps its local level and renews its session more often (the enriched heartbeat isn't echoed) — functional, but update the server to benefit from central control.

Global exception capture

Call once at application startup:

IDOC.Logs.NLog.CaptureGlobale.Activer();

This hooks AppDomain.UnhandledException (logged as Fatal, logs flushed before the process dies) and TaskScheduler.UnobservedTaskException (logged as Error, then marked observed).

For WPF applications, also hook the dispatcher:

// App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    IDOC.Logs.NLog.CaptureGlobale.Activer();
    DispatcherUnhandledException += (_, args) =>
    {
        NLog.LogManager.GetCurrentClassLogger().Fatal(args.Exception, "Exception non gérée (dispatcher WPF).");
        NLog.LogManager.Flush(TimeSpan.FromSeconds(3));
        // args.Handled = true; // uncomment to keep the app alive
    };
}

The target keeps a circular buffer of the last 30 log events (all levels, including those below NiveauEnvoi). When a Warn, Error or Fatal event is sent, the payload's Contexte field carries a JSON object with:

  • Breadcrumbs — the buffered events preceding the error (HH:mm:ss.fff [Level] Logger — Message)
  • Utilisateur — Windows user name
  • Os — OS version string
  • UptimeProcess — process uptime (d.hh:mm:ss)
  • MemoireProcessMo — process working set in MB

For events below Error, Contexte is null — the wire format is unchanged from 1.0.x for them.

Correlation id / scope properties

Any property pushed onto the NLog scope (ScopeContext.PushProperty) is captured into Contexte on every transmitted log line — automatically propagated to all logs emitted inside the scope (including across async/await). Typical use: a per-request correlation id set once in middleware.

// ASP.NET Core middleware, once per request
using (NLog.ScopeContext.PushProperty("Cid", correlationId))
{
    await next(context); // every log emitted downstream carries Cid in Contexte
}

Since 1.4.0, Cid is a dedicated, indexed column on the server (WHERE Cid = '…' ORDER BY Horodatage reconstructs a full user journey); other whitelisted scope properties land in the Contexte JSON. Consumers that never push a scope property see no change.

1.4.0 requires an up-to-date IDOC.Logs.Serveur (chunk reassembly + heartbeat echo). Deploy the server first; clients ≤ 1.3.0 keep working unchanged against the new server.

JSON payload

Each log entry is transmitted as a UTF-8 JSON object:

{
  "Horodatage":  "2026-06-20T12:34:56.789Z",
  "Niveau":      "Info",
  "Logger":      "MyNamespace.MyClass",
  "Message":     "Operation completed",
  "Exception":   null,
  "Application": "MyApp",
  "Machine":     "SERVER01",
  "Version":     "1.2.0",
  "Contexte":    null
}

Requirements

Dependencies

License

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.0 89 7/13/2026
1.4.0 93 7/12/2026
1.3.0 102 7/11/2026
1.2.0 115 7/7/2026
1.1.1 104 7/6/2026
1.1.0 91 7/5/2026
1.0.3 112 6/24/2026
1.0.2 99 6/20/2026
1.0.1 98 6/20/2026
1.0.0 99 6/20/2026