I have a piece of code for setting up serilog based on some custom configuration combined with hosting environment. E.g. the application writes to one sink in development and another sink in production.
I'm trying to figure out how to write tests for this piece of code. Basically, I want to write a test that checks that a sink only is added if the environment name is set to a given value, and that the sink configuration, like log file path, respects the custom configuration that I provide.
But I haven't had any luck finding any way of getting values out of the LoggingConfiguration
...
Anyone knows if this is possible?
For example, if you are using Serilog you should configure Log. Logger and LibLog will use it. Also you can disable logging by setting LogProvider. IsDisabled to true . "
To mock an ILogger<T> object, we can use Moq library to instantiate a new Mock<ILogger<T>>() object. Make sure you have installed the latest Moq package (v4. 15.1 as of Nov. 16, 2020, which contains an update to support “nested” type matchers).
Unfortunately Serilog does not expose the list of Sinks that have been configured, so your only option at the moment would be to use Reflection.
If you poke around Serilog's source code, you'll see that it groups all configured sinks into an instance of an internal class SafeAggregateSink
which is responsible emitting the logs to the different sinks setup, and holds an array with all the configured sinks in a private field called _sinks
.
Here is a simple example:
var log = new LoggerConfiguration()
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Verbose)
.WriteTo.File(path: "log.txt", restrictedToMinimumLevel: LogEventLevel.Verbose)
.CreateLogger();
var aggregateSinkFieldInfo = log.GetType()
.GetField("_sink", BindingFlags.Instance | BindingFlags.NonPublic);
var aggregateSink = (ILogEventSink)aggregateSinkFieldInfo?.GetValue(log);
var sinkEnumerableFieldInfo = aggregateSink?.GetType()
.GetField("_sinks", BindingFlags.Instance | BindingFlags.NonPublic);
var sinks = (ILogEventSink[])sinkEnumerableFieldInfo?
.GetValue(aggregateSink);
if (sinks != null)
{
foreach (var sink in sinks)
{
Console.WriteLine(sink.GetType().FullName);
}
}
This should output:
Serilog.Sinks.SystemConsole.ConsoleSink
Serilog.Sinks.File.FileSink
N.B.: Keep in mind that Serilog wraps sinks in some cases, so you might need to handle that, before you can find the sink you're looking for. For example, if you restrict the minimum level of a sink, your sink will be wrapped into a RestrictedSink
, so you'll have to get a hold of its _sink
field to get the "real" sink you're looking for.
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