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

时间:2018-01-30 07:57:03

标签: c# asp.net-mvc entity-framework serilog

我正在测试Serilog是否正在使用实体框架的SaaS应用程序。 我注意到,如果没有处理加载对象的上下文,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方法而不是使用@。当然我们可以决定不使用@ -operator,但是如果有人忘记并且应用程序因此而失败怎么办?在代码审查中很容易错过@。我不想为Serilog操作构建一个包装器,只是为了防止使用@。

以下内容将阻止使用@ -operator:

            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接收器并且无法访问ApplicationInsights等?

1 个答案:

答案 0 :(得分:1)

我猜测Serilog因实体中的导航属性而挂起,这很容易导致整个数据库被加载。我发现an issue on a Serilog项目似乎描述了同样的问题。

在那个问题中,他们说:

  

Serilog已经做到了   有最大深度限制;它默认设置为10,但您可以使用   Destructure.ToMaximumDepth(n)减少它。

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

还有this NuGet package允许您对不想记录的属性或字段使用NotLogged属性。哪个会起作用,但如果你忘记它在导航属性的某个地方,它仍然很容易被遗漏。

由于Serilog为您提供了自定义处理解构方式的选项。您可以编写自己的处理程序来处理所有需求,例如最大花费日志记录,或者让它记录堆栈跟踪,说明它试图将对象解构为故障安全。但这取决于你。