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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With