Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logging datetime with ms precision using NLog event context layout renderer

I am trying to log some audit information to a SQL Server 2008 table using NLog 2. In order to be able to pass parameters to the SQL insert query, I'm using LogEventInfo and the Event Context Layout Renderer.

The logging itself works but the datetime is stored with only second precision. I want to be able to store with millisecond precision but have not found anything that shows me how to do this.

This is the C# code where I log the event:

private void LogMessage(DateTime requestDateTime)
{
    LogEventInfo theEvent = new LogEventInfo(LogLevel.Debug, "", "Pass my custom value");
    theEvent.Properties["RequestDate"] = requestDateTime;
}

This is the target I have in my NLog.config configuration:

<target xsi:type="Database"
      name="SqlLog"
      dbProvider="sqlserver"
      connectionString="server=localhost;database=Test;integrated security=sspi">
  <commandText>
    INSERT [dbo].[ApiLog]
    (
        [ServerName], [RequestDate]
    )
    VALUES (@ServerName, @RequestDate);
  </commandText>
  <parameter name="@ServerName" layout="${machinename}"/>
  <parameter name="@RequestDate" layout="${event-context:item=RequestDate}"/>
</target>

There is a workaround I have found using theEvent.Properties["RequestDate"] = requestDateTime.ToString("yyyy-MM-dd HH:mm:ss.fff") but I would prefer not to have to do this because then you may run into problems with date time formatting and culture.

Does anyone know of a way that I can change the precision with config in NLog.config?

like image 701
james.christou Avatar asked Nov 10 '22 12:11

james.christou


1 Answers

It looks like the EventContextLayoutRenderer uses Convert.ToString which will lose the precision you are looking for:

public class EventContextLayoutRenderer : LayoutRenderer
{
    //....

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        object value;

        if (logEvent.Properties.TryGetValue(this.Item, out value))
        {
            builder.Append(Convert.ToString(value, CultureInfo.InvariantCulture));
        }
    }
}

As you probably know (and I'm not sure if it's helpful in your situation), but there is a Date layout where you can specify the format and/or a LongDate one which will provide something like 2014-01-01 12:12:12.1234

EDIT

For what it's worth, you can add a customer layout renderer very easily

[LayoutRenderer("event-context-dateTime")]
public class DateTimeContextLayoutRenderer : EventContextLayoutRenderer
{
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        object value;

        if (logEvent.Properties.TryGetValue(this.Item, out value))
        {
            //Your code here
        }
    }
}

And in your configuration

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <extensions>
    <add assembly="YourAssembly"/>
  </extensions>
  <targets>
    <target xsi:type="File" name="file"  fileName="c:\temp\NlogLayout.txt" 
     layout="${longdate} ${event-context-dateTime:item=RequestDate}" />
   ...
</nlog>
like image 113
Joe Avatar answered Nov 14 '22 21:11

Joe