解构 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 为您提供了自定义解构处理方式的选项。您可以只编写自己的处理程序来处理您的所有要求,例如记录日志的最大时间,或者让它记录一个堆栈跟踪,说明它正在尝试将对象解构为故障安全。但这取决于你。