Skip to content

How to write a custom target for structured logging

Rolf Kristensen edited this page Jun 22, 2025 · 17 revisions

Introduced with NLog 4.5

It is really easy:

  • Create a class that inherits from NLog.Targets.TargetWithContext
  • Override the Write(LogEventInfo logEvent) method.
  • In the body of this method invoke this.RenderLogEvent(this.Layout, logEvent) to get the message text, and invoke this.GetAllProperties(logEvent) to get structured properties.

⚠️ Don't forget to register your custom component when loading NLog config!

See also the updated How to write a custom async target

Example

using NLog;
using NLog.Config;
using NLog.Targets;
 
namespace MyNamespace 
{ 
    [Target("MyFirst")] 
    public sealed class MyFirstTarget : TargetWithContext
    { 
        public MyFirstTarget()
        {
            this.IncludeEventProperties = true; // Include LogEvent Properties by default
        }
 
        public Layout Host { get; set; } = "localhost";
 
        protected override void Write(LogEventInfo logEvent) 
        { 
            string logMessage = this.RenderLogEvent(this.Layout, logEvent); 
            string hostName = this.RenderLogEvent(this.Host, logEvent); 
            IDictionary<string,object> logProperties = this.GetAllProperties(logEvent);
            SendTheMessageToRemoteHost(hostName, logMessage, logProperties); 
        } 
 
        private void SendTheMessageToRemoteHost(string hostName, string message, IDictionary<string, object> properties) 
        { 
            // TODO - write me 
        } 
    } 
}

TargetWithContext Features

Additional Context Properties

Users can easily configure additional context information:

<target type="MyFirst" name="first">
   <contextproperty name="MachineName" layout="${machinename}" />
   <contextproperty name="ThreadId" layout="${threadid}" />
</target>

Without needing to inject the details upfront when doing the logging. It is automatically captured by the NLog engine.

Include ScopeContext

ScopeContext Properties can be used to provide context-specific details (Ex. request-correlationid from ILogger.BeginScope).

To automatically capture properties injected into ScopeContext (Before NLog 5.0 it was called IncludeMDLC)

<target type="MyFirst" name="first" includeScopeProperties="true">
   ...
</target>

Custom Merge Properties

TargetWithContext will by default ensure that all captured property-values are included in output, and will automatically generate new unique key-name when name-collission. If wanting to merge properties, so one context can override another context, then one can do it like this:

<target type="MyFirst" excludeProperties="RequestId">
     <contextproperty name="RequestId" layout="${event-properties:RequestId:whenEmpty=${scope-property=RequestId:whenEmpty=DefaultValue}}" />
</sometarget>

Instead of DefaultValue then you could also use one of the NLog LayoutRenderers available. Ex. ${aspnet-TraceIdentifier} or ${activity:property=TraceId}. Or alternative skip whenEmpty=DefaultValue and rely on IncludeEmptyValue="false" (default).

Clone this wiki locally
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy