alefranz / MELT

MELT is a free, open source, testing library for the .NET Standard Microsoft Extensions Logging library. It is a solution to easily test logs.
Apache License 2.0
72 stars 5 forks source link

[Question] Serilog destructuring operator #9

Closed zmira closed 4 years ago

zmira commented 4 years ago

Serilog has a destructuring operator @ (https://nblumhardt.com/2016/02/serilog-tip-dont-serialize-arbitrary-objects/) which, when used, tells it to deserialize and log an object passed as argument, instead of simply calling ToString().

How do I tell MELT to use serilog in my tests so that the object destructuring takes place when writing the logs?

alefranz commented 4 years ago

Hi José, apologies for the delay.

I'm really glad of your interest into this library.

The goal of this library is to have a generic test functionality for logs produced by any app or library through the Microsoft.Extensions.Logging, not tied to any specific implementation.

However, while this holds well for libraries, I understand that when writing applications it could make sense to rely on specific features of the logger implementation.

Currently, if you are looking for the structured properties, you could verify for the property named "@something" and verify that it holds the object you are after, however there is no way to test that the message will contain the destructured content, as this library works at the level of Microsoft Extensions Logging.

I was however working in adding example and docs on how to use this in combination with Serilog and you question has motivated me to investigate how to support testing when Serilog is setup to replace the Microsoft.Extensions.Logging Loggers.

I would hopefully have it merged in a few days (work is in #8).

I have a question for you: are you looking to add this in a ASP.NET Core application? if so, do you integrate Serilog using Serilog.AspNetCore or Serilog.Extensions.Logging?

Thank you, Alessio

zmira commented 4 years ago

Hi. Thanks for the reply.

I actually don't need the content of the @ variable, since I am validating the logged message based on a string template. But I was curious to know if the destructuring operator was ever applied.

Yes, this is being used in ASP.NET Core applications, and Serilog is integrated using Serilog.AspNetCore.

alefranz commented 4 years ago

When using Serilog.AspNetCore you have to set up Serilog to use the Microsoft.Estensions.Logging providers, in your Program.cs:

public static readonly LoggerProviderCollection Providers = new LoggerProviderCollection();

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder
                .UseStartup<Startup>()
                .UseSerilog(providers: Providers);
        });

You then have to set up Serilog in the tests, specifying to use the providers, for example using a custom factory.

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup>
    where TStartup : class
{
    public CustomWebApplicationFactory()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
            .Enrich.FromLogContext()
            .WriteTo.Providers(Program.Providers)
            .CreateLogger();
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.UseTestLogging(options =>
        {
            options.UseScopeFromProperties = true;
            options.FilterByNamespace(nameof(YourNamespace));
        });
    }

    protected override void Dispose(bool disposing)
    {
        if (true)
        {
            Log.CloseAndFlush();
        }
    }
}

You don't need to use a WebApplicationFactory<>, you can do that in the initialization of your tests, but be aware that given the Serilog logger is setup on a static global property, you would have to limit multiple test classes to run in parallel (e.g. using [Collection("Serilog Test Collection")]). This is also true if you use more then one WebApplicationFactory<>.

Once it is setup, you can then assert a destructured messaged.

I am updating the README to add this istrcutions as well as looking into helpers to get the Scope (with Serilog it is in a property called Scope) and the properties easily.

Let me know if this works for you!