我正在为使用 Entity Framework 的 SaaS 应用程序测试 Serilog。
我注意到如果尚未处理加载对象的上下文,Serilog 无法处理解构 EF 对象。
Supplier supplier = context.Supplier.Find(6100);
Log.Information("This works and the cost for ToString() is negligible {supp}", supplier);
Log.Fatal("This will cause an Out of Memory error {@supp}", supplier);
Serilog 将尝试延迟加载整个数据库,应用程序将挂起一分钟并崩溃。 Serilog 日志文件将报告 OutOfMemoryException
如何防止其他开发人员不小心执行以下操作并导致意外挂起/崩溃?
if(veryRarelyOccuringEvent)
Log.Information("Supplier {@supplier} just did something, supplier)
我所做的是使用解构策略来防止所有解构,
我宁愿让开发人员明确声明 ToString 方法而不是使用 @。当然,我们可以决定不使用@-operator,但是如果有人忘记了并且应用程序因此而崩溃怎么办? @ 在代码审查中很容易错过。我不想为 Serilog 操作构造一个包装器只是为了防止使用 @。
以下将阻止使用@-operator:
Log.Logger = new LoggerConfiguration()
.Destructure.With<PreventDestructure>()
...
并且只会返回 {}。但是有没有比下面的代码更简单的方法?
public class PreventDestructure : IDestructuringPolicy {
public bool TryDestructure(
object value,
ILogEventPropertyValueFactory propertyValueFactory,
out LogEventPropertyValue result) {
List<LogEventProperty> fieldsWithValues;
fieldsWithValues = new List<LogEventProperty>();
result = new StructureValue(fieldsWithValues);
return true;
}
}
第二个问题:有没有办法指示 Serilog 在日志事件中花费最大 XXXms?如果我使用数据库接收器并且数据库处于离线状态怎么办?如果我使用 AI 接收器并且无法访问 ApplicationInsights 等?
最佳答案
我猜测 Serilog 由于实体中的导航属性而挂起,这很容易导致整个数据库被加载。我找到了 an issue on a Serilog似乎描述了相同问题的项目。
在那个问题上,他们说:
Serilog does already have a maximum depth limit; it's set to 10 by default but you can use Destructure.ToMaximumDepth(n) to reduce it.
您可以尝试将其设置为 1,以防止加载相关实体。但是,我个人认为这不是一个理想的解决方案。
还有this NuGet package允许您使用
NotLogged
您不想记录的属性或字段的属性。哪个可行,但如果您在某处的导航属性上忘记了它,仍然很容易错过。由于 Serilog 为您提供了自定义解构处理方式的选项。您可以编写自己的处理程序来满足您的所有要求,例如最大时间花费日志记录,或者只是让它记录堆栈跟踪,说明它试图将对象解构为故障安全。但这取决于你。
关于c# - 解构 EF 对象会导致 Serilog 内存不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48516514/