簡體   English   中英

如何使用 NLog 將異常記錄為結構化 JSON

[英]How to log exception as structured JSON with NLog

這是代碼:

try
{
    throw new AssertionException("This is exceptional");
}
catch (AssertionException ex)
{
    // Rider nags me to write Error logs with exceptions this way
    logger.Error(ex, "Houston, we have a problem!"); 
}

配置是這樣的:

<targets async="false">
    <target name="NoPiiLog" xsi:type="Memory">
        <layout type="SuppressPiiJsonLayout" includeAllProperties="true" maxRecursionLimit="2"
                excludeProperties="UserId,EmailId" excludeEmptyProperties="true">
            <attribute name="time" layout="${longdate}" />
            <attribute name="level" layout="${level:uppercase=true}" />
            <attribute name="message" layout="${message:raw=true}" />
            <attribute name="exception">
                <layout type="JSonLayout"  includeAllProperties="true" maxRecursionLimit="2"
                        excludeProperties="UserId,EmailId" excludeEmptyProperties="true" />
            </attribute>
            <attribute name="Properties">
                <layout type='JsonLayout' includeAllProperties="true" maxRecursionLimit="2"
                        excludeEmptyProperties="true"/>
            </attribute>
        </layout>
    </target>

SuppressPiiJsonLayout 是我編寫並注冊的 class,它采用最終的 JSON 並將所有 PII 鍵值替換為“*****”。 我不能做的是記錄異常,除非我在消息字符串中包含“{exception}”,在參數中包含異常 object,如下所示:

 logger.Error(ex, "Houston, we have a problem! {exception}", ex); 

這是因為異常不會進入 LogEvent 的 Params 或 Properties,它位於 LogEvent 的 Exception 成員中。 該文檔不涵蓋異常的結構化日志記錄。 https://github.com/NLog/NLog/wiki/How-to-Log-Exceptions

所以你不會認為我的抑制器把事情搞砸了,下面是代碼:

[Layout("SuppressPiiJsonLayout")]
[ThreadAgnostic]
[ThreadSafe]
public class SuppressPiiJsonLayout : NLog.Layouts.JsonLayout
{
    /// <summary>
    /// This digs thru the JObject and replaces the values with "*****".  It recurses thru all the JObjects it
    ///   finds along the way, replacing the values in ExcludeProperties
    /// </summary>
    /// <param name="logEvent">The logging event.</param>

    private void CleanKeys(JObject obj)
    {
        foreach (var entry in obj)
        {
            if(this.ExcludeProperties.Contains(entry.Key))
            {
                obj[entry.Key] = "*****";
            }
            else
            {
                if (obj[entry.Key] is JObject)
                {
                    this.CleanKeys((JObject)obj[entry.Key]);
                }
            }
        }
    }

    /// <summary>
    /// This intercepts the rendering of the formatted message after it is turned into JSON and then cleans
    ///   all of the "ExcludeProperties" from the JSON about to be outputted, recursing thru all the objects
    ///   it finds.  Unlike the ExcludeProperties of the JSONLayout which is practically useless.  It might not be
    ///   the most efficient thing, but considering how immutable anonymous objects are, it is definitely the
    ///   only way I found to implement it.
    /// </summary>
    /// <param name="logEvent">The logging event.</param>
    /// <param name="target"><see cref="StringBuilder"/> for the result</param>
    protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
    {
        var intercept = new StringBuilder();
        base.RenderFormattedMessage(logEvent, intercept);
        var j = JObject.Parse(intercept.ToString());

        this.CleanKeys(j); // Remove all the ExcludeProperties it finds recursively
        target.Append(j.ToString(Formatting.None)); // And then pass the modified version to the target for writing
    }
}

我想我可以修改這段代碼,使 ex.Exception 成為一個命名參數,但似乎 NLOG 應該已經在處理這個了,所以我有點難過。

是的, LogEventInfo.Exception不包含在LogEventInfo.Properties中,因此在使用includeAllProperties="true"時不會包含它:

而不是這樣做:

<attribute name="exception">
    <layout type="JSonLayout" includeAllProperties="true" maxRecursionLimit="2"
    excludeProperties="UserId,EmailId" excludeEmptyProperties="true" />
</attribute>

然后你可以這樣做( encode="false"是為了避免對來自format=@的 json 輸出進行編碼):

<attribute name="exception" layout="${exception:format=@}" encode="false" />

另見: https://github.com/NLog/NLog/wiki/How-to-use-structured-logging#output-captured-properties

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM