Layout renderers can capture, format and output additional context details that can be used by NLog Layouts. There are 2 ways to create a custom layout renderer.
LayoutRenderer
that also supports additional configuration options.⚠️ Don't forget to register your custom component when loading NLog config!
NLog 4.7 introduces a fluent registration API using LogManager.Setup()
, where you create a layout renderer with a lambda:
NLog.LogManager.Setup().SetupExtensions(s => s.RegisterLayoutRenderer("trace_id", (logevent) => CorrelationIdentifier.TraceId.ToString()) );
NLog 4.4 was the first edition to support lambda function will accept 1 or 2 parameters and should return a string
.
logEventInfo
.logEventInfo
and the current NLog config.Examples
//register ${text-fixed} LayoutRenderer.Register("text-fixed", (logEvent) => "2"); //register ${trace-identifier} LayoutRenderer.Register("trace-identifier", (logEvent) => HttpContext.Current.TraceIdentifier); //Using logEventInfo, ${message-length} LayoutRenderer.Register("message-length", (logEvent) => logEvent.FormattedMessage.Length); //Using config, ${targetCount} LayoutRenderer.Register("targetCount",(logEvent, config) => config.AllTargets.Count);
Need the HTTP-context (e.g. Request, Session etc) for ASP.NET or ASP.NET Core?
Include the NLog.Web (ASP.NET Classic) or NLog.Web.AspNetCore nuget-package.
And usage:
using NLog.Web.LayoutRenderers; AspNetLayoutRendererBase.Register("SessionItem1", (logEventInfo, httpContext, loggingConfiguration) => httpContext.Session["SessionItem"]); // usage ${SessionItem1}
Create a class that inherits from NLog.LayoutRenderers.LayoutRenderer
, set the [LayoutRenderer("your-name")]
on the class and override the Append(StringBuilder builder, LogEventInfo logEvent)
method. Invoke in this method builder.Append(..)
to render your custom layout renderer.
We create a ${hello-world}
layout renderer, which renders..."hello world!".
[LayoutRenderer("hello-world")] public class HelloWorldLayoutRenderer : LayoutRenderer { protected override void Append(StringBuilder builder, LogEventInfo logEvent) { builder.Append("hello world!"); } }How to pass configuration options to the layout render?
Use public class-properties for configuring the LayoutRenderer:
[LayoutRenderer("hello-world")] public class HelloWorldLayoutRenderer : LayoutRenderer { /// <summary> /// New special option /// </summary> [DefaultParameter] public string SpecialOption{ get; set; } /// <summary> /// New extra option /// </summary> public bool ExtraOption{ get; set; }
The [DefaultParameter]
-attribute can only be assigned to one class-property, and gives the ability to assign the class-property-value without specifying the class-property-name.
Example usages:
${hello-world:Bonus}
- Assigns SpecialOption
= Bonus
.${hello-world:SpecialOption=Bonus}
- Assigns SpecialOption
= Bonus
.${hello-world:ExtraOption=true}
- Assigns ExtraOption
= true
.${hello-world:Bonus:ExtraOption=true}
- Assigns SpecialOption
= Bonus
and ExtraOption
= true
.If additional option-validation are required, then override void InitializeLayoutRenderer()
and implement the necessary validation, and throw NLogConfigurationException("...")
when issues are detected.
NLog will automatically capture relevant context state, when using AsyncWrapper-target to perform actual writing on background-thread (to avoid logging objects after they have been disposed). The following class-attributes can used for the LayoutRenderer that enables additional performance:
[ThreadAgnostic]
LayoutRenderer does not capture state from the application-thread logging. Ex. ${threadid}
cannot be [ThreadAgnostic]
.
For LayoutRenderer marked as [ThreadAgnostic]
then NLog can skip the overhead of capturing state.
If just a single LayoutRenderer in a Layout is not marked as [ThreadAgnostic]
, then NLog introduces the overhead of state capture.
[ThreadSafe]
Introduced with NLog 4.5.3, and made obsolete with NLog 5.0 that expects all to be threadsafe.
LayoutRenderer will render correct output regardless of the number of application-threads running inside.
For LayoutRenderer marked as [ThreadSafe]
then NLog will skip using "global" locks when capturing state, thus application-threads will not experience lock-congestion inside NLog.
If just a single LayoutRenderer in a Layout is not marked as [ThreadSafe]
, then NLog introduces the overhead of "global" lock when doing state capture.
Example of class-attributes for LayoutRenderer:
using NLog.Config; [LayoutRenderer("hello-world")] [ThreadAgnostic] public class HelloWorldLayoutRenderer : LayoutRenderer { protected override void Append(StringBuilder builder, LogEventInfo logEvent) { builder.Append("hello world!"); } }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-names.
[LayoutRenderer("hello-world")] // ${hello-world} [LayoutRenderer("hello-earth")] // ${hello-earth} public class HelloWorldLayoutRenderer : LayoutRenderer {
The type-alias can then be used when wanting to use the LayoutRenderer in NLog SimpleLayout.
Notice NLog 5.0 automatically ignores dashes -
in type-alias, so no extra alias is needed for this: Ex. ${helloworld}
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4