Skip to content

How to write a custom target

Rolf Kristensen edited this page Apr 13, 2023 · 29 revisions

It’s really easy:

  1. Create a class that inherits from NLog.Targets.TargetWithLayout
  2. Override the Write() method.
  3. In the body of the method invoke this.Layout.Render() to get the message text, then send the text to the destination media.

Don't forget to register your custom target!

See also the updated How to write a custom target for structured logging

See also the updated How to write a custom async target

Example

This is a skeleton target that writes messages to the specified host:

using NLog;
using NLog.Config;
using NLog.Targets;
 
namespace MyNamespace 
{ 
    [Target("MyFirst")]
    public sealed class MyFirstTarget: TargetWithLayout 
    { 
        public MyFirstTarget()
        {
            this.Host = "localhost";
        }
 
        [RequiredParameter] 
        public string Host { get; set; }
 
        protected override void Write(LogEventInfo logEvent) 
        { 
            string logMessage = RenderLogEvent(this.Layout, logEvent);
            string hostName = RenderLogEvent(this.Host, logEvent);
            SendTheMessageToRemoteHost(hostName, logMessage);
        } 
 
        private void SendTheMessageToRemoteHost(string hostName, string message) 
        { 
            // TODO - write me 
        } 
    } 
}

How to pass configuration options to the target?

In the example above then one can see how the Host-property is used. Having a public property that sets the required configuration parameters is enough for NLog to use it.

Each attribute that you put in the <target /> definition gets passed to the appropriate public property. NLog takes care of the appropriate conversions necessary so that you can use integer, string, datetime, boolean parameters. Check also Properties-constraints-for-custom-extensions

It is recommended to use NLog Layouts or NLog Layout<T> for NLog Target Configuration options, as it will allow users to provide configuration-values from NLog LayoutRenderers (Ex. from appsettings.json, app.config or environment-variables)

How to handle object lifetime

When needing to create interfaces to external framework or start background-threads, then it is recommended to override InitializeTarget and close/release resources again in CloseTarget.

namespace MyNamespace
{
    [Target("MyFirst")]
    public sealed class MyFirstTarget: TargetWithLayout
    {
        protected override void InitializeTarget()
        {
            base.InitializeTarget();
            // TODO Custom Init Logic
        }

        protected override void CloseTarget()
        {
            // TODO Custom Close Logic
            base.CloseTarget();
        }
    }
}

It is possible for the same target object to be initialized and closed many times during the lifetime of the application. It is recommended not to use the constructor to start background-threads or initialize interfaces, but merely focus on setting up initial state without starting anything. It is possible to override the Dispose-method, but this method will only be called at the end of application-lifetime.

Multiple type-alias attributes

NLog 5.0 enables you to have multiple type-aliases for a single class. Before one had to inherit from the same class to provide additional type-aliases.

[Target("MyFirst")]
[Target("MyInitial")]
public sealed class MyFirstTarget: TargetWithLayout 
{

The type-alias can then be used when wanting to use the target in the NLog Configuration File. Ex. <target type="MyFirst" name="..." />

Notice NLog 5.0 automatically ignores dashes - in type-aliases, so no extra alias is needed for this: Ex. <target type="My-First" name="..." />

Clone this wiki locally