【问题标题】:NLog Custom Target for JSNLogJSNLog 的 NLog 自定义目标
【发布时间】:2017-10-06 14:32:22
【问题描述】:

我目前正在开发一个应用程序,它利用 NLog 进行 .NET 日志记录和 JSNLog 将日志从 Javascript 发送到 NLog 进行日志记录。这些日志存储在 SQL 数据库中。

SQL 数据库有多个用于 NLog 的列,例如 Message、StackTrace、InnerException 和 AdditionalInfo。但是,当我像这样从 JSNLog 记录一些东西时

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;
}

它被 NLog 简单地解释为一个简单的字符串日志而不是错误,因此它只是将这个巨大的 JSON 字符串添加到 AdditionalInfo 列,并将 Message、StackTrace 和 InnerException 列留空。这使得阅读日志变得更加困难。

我希望能够解析 JSNLog 调用发送的 JSON 并将其发送到适当的 NLog 变量,即:

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

将导致 Message 和 InnerException 列包含 JSON 中发送的数据。解析不是问题,因为我知道如何做到这一点,但我不确定如何拦截对 NLog 的调用,因此我可以在将 JSON 正确发送到 NLog 之前对其进行解析。

我已经考虑写一个custom NLog target,这似乎并不难,但我不确定如何正确地将我解析的 JSON 传递给 Nlog?


编辑#1:为@Julian 更新了 NLog.config 这是我的新 NLog.config,但来自新 Write 函数的日志没有传递到 database 目标。

<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>

【问题讨论】:

    标签: c# logging nlog


    【解决方案1】:

    在这种情况下,创建一个 TargetWrapper 是一个很好的解决方案,这样您就可以将它与其他目标结合起来。

    配置将如下所示:

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

    为此所需的代码:从WrapperTargetBase 继承并覆盖Write。例如

    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)
        }
    }
    

    不要忘记注册您的包装器 (see here) 并更新您的配置以写入包装器而不是包装的目标。

    【讨论】:

    • 感谢您的回答!我已经注册了我的 Wrapper,我可以看到消息传递给我的自定义 Write 函数,但是一旦我将 LogEvent.Exception 更改为使用 JSON 中的数据,write 函数就结束了,新的日志是从未在wrapper 中传递给我的target。有什么我想念的吗?我已更新 OP 以包含我的新 NLog.config
    • 哎呀,从示例中剥离了太多内容。您需要拨打WrappedTarget.WriteAsyncLogEvent(logEvent),我已经更新了示例
    • 太好了,更新后的示例效果很好!不过,我还有几个问题。我可以通过编写自定义异常类来更改Exception Type,但我不确定如何设置Call SiteStack Trace 变量。我注意到有一个 SetStackTrace 函数,但这只需要一个 .NET StackTrace 参数,而且我的堆栈来自字符串中的 Javascript。我也希望能够将CallSite 设置为字符串。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 2014-03-25
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多