Serilog的例外解构
Serilog有一种方便的方法来解析对象,如下例所示:
logger.Debug(exception, "This is an {Exception} text", exception); logger.Debug(exception, "This is an {@Exception} structure", exception);
第一行导致记录器将exception记录为纯文本(通过调用ToString()),第二行使记录器将exception属性写为单独的字段。 但是这个重载呢:
logger.Debug(exception, "This is an exception", exception);
这个作为第一个参数使用exception,它总是写成一个字符串。 我想要做的是以结构化的方式启用日志记录exception。 是否可以配置Serilog来实现这一目标?
UPDATE。 我想这个问题会导致记录exception的另一个方面:如何确保消息通过exception属性进行丰富(因此它们以结构化的方式记录到富散问件,如Elasticsearch),而无需将所有exception属性写入呈现的文本消息(所以纯文本记录器没有填满大量的exception细节)。
有一个讨论这个的论坛post ,其中提出了几个解决方案。 Thomas Bolon创建了一个你可以在Gist中找到的“exception解构”扩展。
在这种情况下,您只使用以下语法:
logger.Debug(exception, "This is an exception");
无需将exception添加到格式字符串中。
要确保将exception打印到文本接收器,请确保输出模板中包含{Exception}
。 标准内置的已经有了这个,例如:
outputTemplate: "{Timestamp} [{Level}] {Message}{NewLine}{Exception}";
看看Serilog.Exceptions日志exception详细信息和Exception.ToString()中未输出的自定义属性。
该库具有自定义代码,用于处理大多数常见exception类型的额外属性,并且只有在内部Serilog.Exceptions不支持exception时才会使用reflection来获取额外信息。
添加NuGet包,然后像这样添加richher:
using Serilog; using Serilog.Exceptions; ILogger logger = new LoggerConfiguration() .Enrich.WithExceptionDetails() .WriteTo.Sink(new RollingFileSink( @"C:\logs", new JsonFormatter(renderMessage: true)) .CreateLogger();
现在,您的JSON日志将补充详细的exception信息甚至自定义exception属性。 下面是从EntityFramework记录DbEntityValidationException时会发生什么的示例(此exception因为具有未包含在.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.Exceptions支持.NET标准并支持许多常见的exception类型而没有reflection,但我们想添加更多,所以请随时贡献。
顶尖 – 人类可读堆栈痕迹
您可以使用Ben.Demystifier NuGet包为您的exception获取人类可读的堆栈跟踪,或者如果您使用Serilog,则可以使用serilog -enrichers-demystify NuGet包。
应该完全避免这种情况。 ElasticSearch和Serilog都没有考虑到您将序列化任意对象的想法。 记录具有冲突形状的对象将导致ElasticSearch中的映射exception。 如果您在NuGet中使用ElasticSearch接收器,则会导致映射冲突的任何内容都将丢失。 Serilog也不处理循环关系,因此这将导致深度限制器自动错误。 有一个项目试图通过解构为字典并将其传递给Serilog来解决这个问题,但是你仍然会看到凌乱的日志和映射exception。
Serilog: https ://nblumhardt.com/2016/02/serilog-tip-dont-serialize-arbitrary-objects/
我发现最好根据您在exception中发现的有用内容来记录exception属性。