Conor Watson
Conor Watson

Reputation: 617

NLog Custom Target for JSNLog

I am currently developing an application which makes use of NLog for .NET logging and JSNLog to send logs from Javascript to NLog for logging. These logs are stored in a SQL database.

The SQL Database has several columns for NLog such as Message, StackTrace, InnerException and AdditionalInfo. However when I log something from JSNLog like so

window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
    JL("databaseLogger").fatalException({
        "msg": "Uncaught Exception",
        "errorMsg": errorMsg, "url": url,
        "line number": lineNumber, "column": column
    }, errorObj);

    return false;
}

It is simply interpreted by NLog as a simple string log and not an error, so it just adds this giant JSON string to the AdditionalInfo column, and leaves the Message, StackTrace and InnerException columns blank. This makes reading the logs much harder.

I'd like to be able to parse this JSON sent by the JSNLog call and send it to the appropriate NLog variable, i.e:

JL("databaseLogger").fatalException({
    "Message": "Uncaught Exception",
    "InnerException": errorMsg,
}, errorObj);

would result in the Message and InnerException columns containing the data sent in the JSON. The parsing is not an issue as I know how to do that, but I am not sure how to intercept the call to NLog so I can parse the JSON before sending it onto NLog correctly.

I've looked into writing a custom NLog target which doesn't seem to hard, but I am not sure how to then pass my parsed JSON to Nlog correctly?


EDIT #1: Updated NLog.config for @Julian Here is my new NLog.config but the Log from the new Write function does not get passed to the database target.

<targets>
    <target xsi:type="ParseJsonWrapper"
        name="JSONParser">
      <target name="database"
         xsi:type="Database"
         connectionStringName="ErrorLog"
         commandText="exec dbo.InsertLog
                            @level,
                            @callSite,
                            @type,
                            @message,
                            @stackTrace,
                            @innerException,
                            @additionalInfo">
        <parameter name="@level" layout="${level}" />
        <parameter name="@callSite" layout="${callsite}" />
        <parameter name="@type" layout="${exception:format=type}" />
        <parameter name="@message" layout="${exception:format=message}" />
        <parameter name="@stackTrace" layout="${exception:format=stackTrace}" />
        <parameter name="@innerException"
                    layout="${exception:format=:innerFormat=ShortType,Message,Method:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}" />
        <parameter name="@additionalInfo" layout="${message}" />
      </target>
    </target>
  </targets>

  <rules>
    <logger levels="Trace,Info,Debug,Error,Warn,Fatal" name="JSLogger" writeTo="JSONParser"/>
  </rules>

Upvotes: 1

Views: 723

Answers (1)

Julian
Julian

Reputation: 36700

In this case, it's a good solution to create a TargetWrapper so you could combine it with other targets.

The config will looks like this:

  <target xsi:type="ParseJsonWrapper"
          name="myWrapper">
    <target xsi:type="File" ...target properties... />
  </target>

The code needed for this: inherit from WrapperTargetBase and override Write. e.g.

using System;
using NLog.Common;
/// <summary>
/// Limits the number of messages written per timespan to the wrapped target.
/// </summary>
[Target("ParseJsonWrapper", IsWrapper = true)]
public class ParseJsonWrapper : WrapperTargetBase
{
    protected override void Write(AsyncLogEventInfo logEvent)
    {
        var json = logEvent.LogEvent.Message;
        // parse json

        // update log event
        logEvent.LogEvent.Exception = new Exception("something");

        // write to wrapped target
        WrappedTarget.WriteAsyncLogEvent(logEvent)
    }
}

Don't forget to register your wrapper (see here) and update your config to write to the wrapper instead of the wrapped target.

Upvotes: 2

Related Questions