'NLog ElasticSearch structuredlogging

I need to send NLog log messages to Kibana. Now I'm using NLog.Targets.ElasticSearch with structuredlogging.json but in this case elastic treats message as string and not as json. In general I need Kibana to treat message as object by fields of which I can make future analytics.

So how to force nlog or NLog.Targets.ElasticSearch to send data to elasticsearch to be treated as json?

Here is what i have now:

  {
    "_index": "logstash-2017.10.12",
    "_type": "logevent",
    "_id": "AV8QvCAHXFqCIKUdDl_1",
    "_score": 1,
    "_source": {
      "@timestamp": "2017-10-12T13:18:05.0609218Z",
      "level": "Error",
      "message": """{"TimeStamp":"2017-10-12T13:18:05.060Z","Level":"Error","LoggerName":"testApp.Program","Message":"error","CallSite":"testApp.Program.Main","error":"error0"}"""
    }
  }

And it needs to be something like this:

  {
    "_index": "logstash-2017.10.12",
    "_type": "logevent",
    "_id": "AV8QvCAHXFqCIKUdDl_1",
    "_score": 1,
    "_source": {
      "@timestamp": "2017-10-12T13:18:05.0609218Z",
      "level": "Error",
      "message": {
        "TimeStamp":"2017-10-12T13:18:05.060Z",
        "Level":"Error",
        "LoggerName":"testApp.Program",
        "Message":"error",
        "CallSite":"testApp.Program.Main",
        "error":"error0"
      }
    }
  }

Current NLog.config looks so:

<target name="elastic" xsi:type="BufferingWrapper" flushTimeout="5000" >
  <target xsi:type="ElasticSearch" layout="${structuredlogging.json}">
  </target>
</target>


Solution 1:[1]

Maybe this will work:

<target name="elastic" xsi:type="BufferingWrapper" flushTimeout="500" >
  <target xsi:type="ElasticSearch">
     <field name="msg" layout="${structuredlogging.json}" layoutType="System.Object" />
  </target>
</target>

Alternative you can do this (Without NLog.StructuredLogging.Json):

<target name="elastic" xsi:type="BufferingWrapper" flushTimeout="500" >
  <target xsi:type="ElasticSearch" includeAllProperties="true">
     <field name="TimeStamp" layout="${date:format=o}" />
     <field name="Level" layout="${level}" />
     <field name="LoggerName" layout="${logger}" />
     <field name="Message" layout="${message}" />
     <field name="CallSite" layout="${callsite}" />
     <field name="error" layout="${exception:format=tostring}" />
  </target>
</target>

Alternative you can do this (Using EcsLayout):

<extensions>
    <add assembly="NLog.Targets.ElasticSearch"/>
    <add assembly="Elastic.Apm.NLog"/>
    <add assembly="Elastic.CommonSchema.NLog"/>
</extensions>
<targets>
   <target xsi:type="ElasticSearch" enableJsonLayout="true">
       <layout xsi:type="EcsLayout" />
   </target>
</targets>

Solution 2:[2]

You can do it with:

<field name="MessageObject" layout="${message}" layoutType="System.Object" />

then make logging with:

_logger.LogInformation("{@ExampleObject}", exampleLoggingObject);

The output is:

 "Message": {
     "ExecutionTime": 12,
     "Level": "Information",
     "Type": "ABC",
     ....
 }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Sean Stayns