Serilog中的异常解构
本文关键字:异常 Serilog | 更新日期: 2023-09-27 18:18:02
Serilog有一种方便的方法来解构对象,如下例所示:
logger.Debug(exception, "This is an {Exception} text", exception);
logger.Debug(exception, "This is an {@Exception} structure", exception);
第一行使记录器将异常记录为纯文本(通过调用ToString()),第二行使记录器将异常属性写入单独的字段。但是这个重载呢:
logger.Debug(exception, "This is an exception", exception);
将异常作为其第一个参数,并且总是写成字符串。我想使之成为可能的是以结构化的方式启用日志异常。是否有可能配置Serilog来实现这一点?
更新。我猜这个问题导致了记录异常的另一个方面:我如何确保消息被异常属性丰富(因此它们以结构化的方式记录到丰富的汇,如Elasticsearch),而不将所有异常属性写入呈现的文本消息(因此纯文本记录器不会充满大量异常细节)。
看一下Serilog。Exceptions记录在exception . tostring()中没有输出的异常细节和自定义属性。
这个库有自定义代码来处理大多数常见异常类型的额外属性,只有在Serilog不支持异常时才会使用反射来获取额外信息。内部异常。
添加NuGet包,然后添加富集器,如下所示:
using Serilog;
using Serilog.Exceptions;
ILogger logger = new LoggerConfiguration()
.Enrich.WithExceptionDetails()
.WriteTo.Sink(new RollingFileSink(
@"C:'logs",
new JsonFormatter(renderMessage: true))
.CreateLogger();
您的JSON日志现在将补充详细的异常信息,甚至自定义异常属性。下面是一个例子,当你从EntityFramework记录一个DbEntityValidationException时会发生什么(这个异常是臭名昭著的,有深度嵌套的自定义属性,不包括在.ToString()
中)。
try
{
...
}
catch (DbEntityValidationException exception)
{
logger.Error(exception, "Hello World");
}
上面的代码记录如下内容:
{
"Timestamp": "2015-12-07T12:26:24.0557671+00:00",
"Level": "Error",
"MessageTemplate": "Hello World",
"RenderedMessage": "Hello World",
"Exception": "System.Data.Entity.Validation.DbEntityValidationException: Message",
"Properties": {
"ExceptionDetail": {
"EntityValidationErrors": [
{
"Entry": null,
"ValidationErrors": [
{
"PropertyName": "PropertyName",
"ErrorMessage": "PropertyName is Required.",
"Type": "System.Data.Entity.Validation.DbValidationError"
}
],
"IsValid": false,
"Type": "System.Data.Entity.Validation.DbEntityValidationResult"
}
],
"Message": "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.",
"Data": {},
"InnerException": null,
"TargetSite": null,
"StackTrace": null,
"HelpLink": null,
"Source": null,
"HResult": -2146232032,
"Type": "System.Data.Entity.Validation.DbEntityValidationException"
},
"Source": "418169ff-e65f-456e-8b0d-42a0973c3577"
}
}
Serilog。异常支持。net标准,并支持许多常见的不带反射的异常类型,但我们想添加更多,所以请随时贡献。
Top Tip -人类可读堆栈跟踪
你可以用Ben。Demystifier NuGet包可以为你的异常获取人类可读的堆栈跟踪;如果你使用Serilog,可以使用Serilog - enricers -demystify NuGet包
有一个论坛讨论这个问题,其中提出了几个解决方案。Thomas Bolon创建了一个"异常解构"扩展,你可以在Gist中找到。
在这种情况下,您只使用以下语法:
logger.Debug(exception, "This is an exception");
不需要在格式字符串中添加异常。
要确保异常被打印到文本接收器,只需确保输出模板中包含{Exception}
。标准的内置代码已经有这个功能了,例如:
outputTemplate: "{Timestamp} [{Level}] {Message}{NewLine}{Exception}";
这应该完全避免。ElasticSearch和Serilog在设计时都没有考虑到要序列化任意对象。记录具有冲突形状的对象将导致ElasticSearch中的映射异常。如果您在NuGet中使用ElasticSearch接收器,任何导致映射冲突的内容都将丢失。此外,Serilog不处理循环关系,因此这将导致深度限制器自标记错误。有一个项目试图通过解构成字典并将其传递给Serilog来解决这个问题,但你仍然会得到混乱的日志和映射异常。
Serilog: https://nblumhardt.com/2016/02/serilog-tip-dont-serialize-arbitrary-objects/
我发现最好根据你在异常中发现的有用内容来具体记录异常属性