Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

configuring NLog's layout to show all the event-context entries

Tags:

c#

nlog

im currently in the process of developing a webapi2 application, and in the stages of conducting my logs using NLog.

in my application i log in a key-value manner using the LogEventInfo.Properties dictionary in this way:

thisController.LogParams.Add("ControllerName",controllerName);
thisController.LogParams.Add("ActionName", actionName);
thisController.LogParams.Add("TotalTime", actionWatch.ElapsedMilliseconds);
LogEventInfo logEvent = new LogEventInfo() 
       { 
           Message = string.IsNullOrEmpty(thisController.LogMessage)? "Finished Successfuly":thisController.LogMessage,
           Level = LogLevel.Info,
           TimeStamp = DateTime.Now
       };
logEvent.Properties.Merge(thisController.LogParams);
logger.Log(logEvent);

everything works fine, however I cant seem to find the way to render the layout so it prints all the key-value entries that are in the LogEventInfo.Properties dictionary.

lets assume my target is a file, then i have to explicitly mention the key name, is there a way to render it to show all the content of the dictionary ? this is how i do it today, where i can log only the entries i know of:

<target name="f1" 
  xsi:type="File" 
  fileName="${basedir}\logs\log.txt" 
  maxArchiveFiles="60" 
  archiveNumbering="Date" 
  archiveDateFormat="yyyyMMdd" 
  archiveEvery="Day" 
  layout="${longdate} : ${callsite:className=true:methodName=true} : ${event-context:item=ControllerName} : ${event-context:item=ActionName} : ${event-context:item=TotalTime} : ${message}" />
like image 369
Ben Guri Avatar asked Feb 22 '15 16:02

Ben Guri


2 Answers

There is a built-in layout renderer in NLog which serves that purpose - ${all-event-properties}. By default it emits all event context properties in key-value style, comma separated.

Checkout the docs for more details https://github.com/NLog/NLog/wiki/All-Event-Properties-Layout-Renderer

like image 179
pkmiec Avatar answered Sep 21 '22 22:09

pkmiec


There's no built-in support that can render all properties at once. If you look at the code in event-context layout renderer then it's only adding single value of property based on item i.e. property name.

You can create your custom Layout renderer that can print all the properties from LogEventInfo. Instead of fetching value of property based on item just add them all to string builder which will get printed to target.

using System;
using System.Globalization;
using System.Text;
using NLog.Config;
namespace CustomLayoutRenderer
{
    /// <summary>
    /// Log event context data.
    /// </summary>
    [LayoutRenderer("event-context-all")]
    public class EventContextLayoutRenderer : LayoutRenderer
    {
        /// <summary>
        /// Renders the specified log event context item and appends it to the specified <see cref="StringBuilder" />.
        /// </summary>
        /// <param name="builder">The <see cref="StringBuilder"/> to append the rendered data to.</param>
        /// <param name="logEvent">Logging event.</param>
        protected override void Append(StringBuilder builder, LogEventInfo logEvent)
        {
            foreach (var item in logEvent.Properties)
            {
                // item is a keyvalue pair object you can custom format the key value as needed.
                builder.Append(Convert.ToString(item.Value, CultureInfo.InvariantCulture));
            }

        }
    }
}

You can register this custom layout renderer using <extension> tag in Nlog configuration file.

<nlog> 
  <extensions> 
    <!-- Add the assembly name which contains the custom layout renderer -->
    <add assembly="MyAssembly"/> 
  </extensions> 
  <targets> 
    <target name="f1" type="file"  layout="${longdate} ${event-context-all}" 
            fileName="${basedir}/logs/logfile.log" />
  </targets> 
</nlog>

This shall print the all properties values only without requiring the item name.

like image 20
vendettamit Avatar answered Sep 23 '22 22:09

vendettamit