我正在为使用实体框架的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 日志文件将报告内存不足异常
如何防止其他开发人员意外执行以下操作并导致意外挂起/崩溃?
if(veryRarelyOccuringEvent)
Log.Information("Supplier {@supplier} just did something, supplier)
我所做的是使用解构策略来防止所有解构, 我宁愿让开发人员显式声明 ToString 方法,而不是使用 @。当然,我们可以决定不使用@运算符,但是如果有人忘记并且应用程序因此而关闭怎么办?@在代码审查中很容易错过。我不想为Serilog操作构建包装器,只是为了防止使用@。
以下内容将阻止使用 @ 运算符:
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 接收器并且无法访问应用程序见解等?
我猜 Serilog 由于实体中的导航属性而挂起,这很容易导致加载整个数据库。我在Serilog项目上发现了一个问题,似乎描述了同样的问题。
在那个问题上,他们说:
Serilog已经做到了 有最大深度限制;默认情况下设置为 10,但您可以使用 Destructure.ToMaximumDepth(n) 来减少它。
您可以尝试将其设置为 1,以防止加载相关实体。但是,我个人认为这不是一个理想的解决方案。
还有一个 NuGet 包,它允许你对不希望记录的属性或字段使用NotLogged
属性。这将有效,但如果您将其遗忘在某处的导航属性上,仍然很容易错过。
因为Serilog为您提供了自定义解构处理方式的选项。您可以编写自己的处理程序来处理您的所有要求,例如记录所花费的最长时间,或者只是让它记录堆栈跟踪,说明它试图将对象解构为故障安全。但这取决于你。