EF对象的解构会导致Serilog内存耗尽。

5

我正在为一个使用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方法,而不是使用@。当然,我们可以决定不使用@运算符,但如果有人忘记了并且应用程序因此崩溃怎么办呢?在代码审查中很容易忽略@。我不想构建一个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在日志事件中花费最长XXX毫秒?如果我使用数据库 sink 并且数据库脱机了怎么办?如果我使用 AI sink,但无法连接 ApplicationInsights 等情况呢?


在第二个问题上,大多数的 sink 都会异步地将日志记录到外部服务中,因此应用程序应该继续正常运行。 - Nicholas Blumhardt
也许你应该默认关闭懒加载。你真的需要它吗? - Gert Arnold
1个回答

5
我猜测Serilog由于实体中的导航属性而挂起,这很容易导致整个数据库被加载。我在Serilog项目上找到了一个问题,似乎描述了同样的问题。
在那个问题中,他们说:
“Serilog已经有一个最大深度限制;默认情况下设置为10,但您可以使用Destructure.ToMaximumDepth(n)将其减少。”
你可以尝试将其设置为1,以防止加载相关实体。然而,个人认为这不是一个理想的解决方案。
还有这个NuGet包,允许您在不想记录的属性或字段上使用NotLogged属性。这将起作用,但如果您在某个导航属性上忘记了它,仍然很容易错过。
由于Serilog提供了自定义处理解构方式的选项。您可以编写自己的处理程序,以满足所有要求,例如最大日志记录时间,或者只让它记录一个堆栈跟踪表明它正在尝试将对象解构为故障安全。但这取决于您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接