这是代码:
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!"); 
}
配置是这样的:
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!"); 
}
SuppressPiiJsonLayout 是我编写并注册的一个类,它采用最终的 JSON 并将所有 PII 键值替换为“*****”。我不能做的是记录异常,除非我在消息字符串中包含“{exception}”并在参数中包含异常对象,如下所示:
 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"是为了避免对 json 输出进行编码format=@):
<attribute name="exception" layout="${exception:format=@}" encode="false" />
另请参阅: https: //github.com/NLog/NLog/wiki/How-to-use-structed-logging#output-captured-properties