c# - 如何让我的异常输出为带有 NLOG 的结构化 JSON
问题描述
这是代码:
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 是我编写和注册的一个类,它采用最终的 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-structured-logging#output-captured-properties
推荐阅读
- asynchronous - 当 typeahead 的值已经异步时,Typeahead 会跳过异步请求
- javascript - Chart.js 标签 - 水平条形图的 Y 轴上需要两个标签
- rust - Rust:在`impl`中的函数中返回对成员变量的引用
- c - C - 哈希表键的链表
- python-3.x - 使用 LXML.HTML 和 Xpath 进行 WebScraping
- java - 如何在不重新启动 Activity 的情况下更新 Firebase 数据库中的数据
- go - 在 Go 中处理混合类型的哈希的替代方案
- sql - 从查询结果创建新表
- kentico - 具有 URL“路径或模式”功能的 Kentico 自定义页面 URL
- python-3.x - 克服机器学习模型早期收敛的最佳方法