-
Notifications
You must be signed in to change notification settings - Fork 1.4k
How to write a custom target for structured logging
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 invokethis.GetAllProperties(logEvent)
to get structured properties.
See also the updated How to write a custom async target
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
}
}
}
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.
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>
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).
- Troubleshooting Guide - See available NLog Targets and Layouts: https://nlog-project.org/config
- Getting started
- How to use structured logging
- Troubleshooting
- FAQ
- Articles about NLog
-
All targets, layouts and layout renderers
Popular: - Using NLog with NLog.config
- Using NLog with appsettings.json