解构 EF 对象会导致 Serilog 内存不足

Pit*_*att 5 c# asp.net-mvc entity-framework serilog

我正在为使用实体框架的 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);
Run Code Online (Sandbox Code Playgroud)

Serilog 将尝试延迟加载整个数据库,应用程序将挂起一分钟并崩溃。Serilog 日志文件将报告 OutOfMemoryException

如何防止其他开发人员不小心执行以下操作并导致意外挂起/崩溃?

if(veryRarelyOccuringEvent)
    Log.Information("Supplier {@supplier} just did something, supplier)
Run Code Online (Sandbox Code Playgroud)

我所做的是使用解构策略来防止所有解构,我宁愿让开发人员明确声明 ToString 方法而不是使用 @。当然,我们可以决定不使用@-operator,但是如果有人忘记了并且应用程序因此而崩溃怎么办?@ 在代码审查中很容易错过。我不想为 Serilog 操作构造一个包装器只是为了防止使用 @。

以下将阻止使用@-operator:

            Log.Logger = new LoggerConfiguration()
                .Destructure.With<PreventDestructure>()
            ...
Run Code Online (Sandbox Code Playgroud)

并且只会返回 {}。但是有没有比下面的代码更简单的方法?

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;

    }
}
Run Code Online (Sandbox Code Playgroud)

第二个问题:有没有办法指示 Serilog 在日志事件中花费最大 XXXms?如果我使用数据库接收器并且数据库处于离线状态怎么办?如果我使用 AI 接收器并且无法访问 ApplicationInsights 等?

小智 5

我猜测 Serilog 由于实体中的导航属性而挂起,这很容易导致整个数据库被加载。我在 Serilog项目上发现了一个似乎描述相同问题的问题。

在那一期他们说:

Serilog 确实已经有最大深度限制;默认情况下它设置为 10,但您可以使用 Destruct.ToMaximumDepth(n) 来减少它。

您可以尝试将其设置为 1,以防止加载相关实体。然而,我个人认为这不是一个理想的解决方案。

还有一个 NuGet 包NotLogged,允许您在不希望记录的属性或字段上使用属性。这是可行的,但如果您将其忘记在导航属性上的某个地方,仍然很容易错过。

Serilog 为您提供了自定义解构处理方式的选项。您可以编写自己的处理程序来满足您的所有要求,例如记录花费的最大时间,或者只是让它记录堆栈跟踪,表明它正在尝试解构对象作为故障安全。但这取决于你。