Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destructuring EF-objects will cause Serilog to run out of memory

Tags:

I am testing Serilog for a SaaS application which is using Entity Framework. I noticed that Serilog can not handle destructuring EF-objects if the context from which the object is loaded has not been disposed .

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 will try to lazy load the whole database, the app will hang for a minute and crash. Serilog log file will report OutOfMemoryException

how to prevent other developers from accidentally doing something like the following and causing unexpected hangs/crashes?

if(veryRarelyOccuringEvent)
    Log.Information("Supplier {@supplier} just did something, supplier)

What I did was to use a destructuring policy to prevent all destructuring, I'd rather have the developers explicitly declaring a ToString method than to use @. Of course we can decide not to use the @-operator but what if someone forgets and the app comes down because of it? The @ is very easy to miss in code review. I would not like to construct a wrapper for Serilog operations just to prevent the use of @.

The following will prevent the use of the @-operator:

            Log.Logger = new LoggerConfiguration()
                .Destructure.With<PreventDestructure>()
            ...

And will just return {}. But is there a simpler way than the code below?

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;

    }
}

2nd question: Is there a way to instruct Serilog to spend max XXXms in a logging event? How about if I use a database sink and the database is offline? And if I use AI sink and ApplicationInsights cannot be reached etc?

like image 771
Pitchmatt Avatar asked Jan 30 '18 07:01

Pitchmatt


1 Answers

I'm guessing that Serilog hangs due to navigation properties in your entities which can easily result in your entire database being loaded. I found an issue on a Serilog project that seems to describe the same issue.

In that issue they say:

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.

You could try to set it to 1, to prevent loading related entities. However, personally I don't think this is a desirable solution.

There is also this NuGet package that allows you to use an NotLogged attribute on properties or fields that you do not want logged. Which would work, but is still easy to miss if you forget it on a navigation property somewhere.

As Serilog provides you with the option to customize the way destructuring is handled. You could just write your own handler that takes care of all your requirements such as a maximum time spend logging, or just let it log a stacktrace stating it was trying to destructure an object as a fail-safe. But that's up to you.

like image 69
RMH Avatar answered Sep 21 '22 13:09

RMH