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属性。