解构 EF 对象将导致 Serilog 运行 内存不足
Destructuring EF-objects will cause Serilog to run out of memory
我正在为使用 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
如何防止其他开发者不小心做出类似下面的事情而造成意外hangs/crashes?
if(veryRarelyOccuringEvent)
Log.Information("Supplier {@supplier} just did something, supplier)
我所做的是使用解构策略来防止所有解构,
我宁愿让开发人员显式声明 ToString 方法也不愿使用 @。当然我们可以决定不使用 @-operator 但如果有人忘记了并且应用程序因此而崩溃怎么办? @ 在代码审查中很容易被遗漏。我不想为 Serilog 操作构造一个包装器只是为了防止使用 @.
以下将阻止使用@-运算符:
Log.Logger = new LoggerConfiguration()
.Destructure.With<PreventDestructure>()
...
并且只会 return {}。但是有没有比下面的代码更简单的方法呢?
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 为您提供了自定义解构处理方式的选项。您可以只编写自己的处理程序来处理您的所有要求,例如记录日志的最大时间,或者让它记录一个堆栈跟踪,说明它正在尝试将对象解构为故障安全。但这取决于你。
我正在为使用 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
如何防止其他开发者不小心做出类似下面的事情而造成意外hangs/crashes?
if(veryRarelyOccuringEvent)
Log.Information("Supplier {@supplier} just did something, supplier)
我所做的是使用解构策略来防止所有解构, 我宁愿让开发人员显式声明 ToString 方法也不愿使用 @。当然我们可以决定不使用 @-operator 但如果有人忘记了并且应用程序因此而崩溃怎么办? @ 在代码审查中很容易被遗漏。我不想为 Serilog 操作构造一个包装器只是为了防止使用 @.
以下将阻止使用@-运算符:
Log.Logger = new LoggerConfiguration()
.Destructure.With<PreventDestructure>()
...
并且只会 return {}。但是有没有比下面的代码更简单的方法呢?
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 为您提供了自定义解构处理方式的选项。您可以只编写自己的处理程序来处理您的所有要求,例如记录日志的最大时间,或者让它记录一个堆栈跟踪,说明它正在尝试将对象解构为故障安全。但这取决于你。