Serilog.FluentDestructuring 1.0.1

dotnet add package Serilog.FluentDestructuring --version 1.0.1
                    
NuGet\Install-Package Serilog.FluentDestructuring -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Serilog.FluentDestructuring" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Serilog.FluentDestructuring" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Serilog.FluentDestructuring" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Serilog.FluentDestructuring --version 1.0.1
                    
#r "nuget: Serilog.FluentDestructuring, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Serilog.FluentDestructuring@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Serilog.FluentDestructuring&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Serilog.FluentDestructuring&version=1.0.1
                    
Install as a Cake Tool

Serilog.FluentDestructuring

This package makes it possible to manipulate how complex objects are logged to Serilog using Fluent API.

Motivation

The Destructurama.Attributed package provides convenient ways to configure Serilog complex object logging by using attributes. With these, you can easily ignore some properties, apply masking and so on. But this attribute-based approach does introduce a dependency on Serilog in projects where such a dependency may be undesirable (a similar issue exists with Entity Framework Core and its attribute-based model configuring approach). This package emerged out of the need to eliminate this dependency and provide another way for the developers to configure complex objects logging using a Fluent API.

Installation

Download from NuGet

Package Manager
NuGet\Install-Package Serilog.FluentDestructuring -Version *version_number*
.NET CLI
dotnet add package Serilog.FluentDestructuring --version *version_number*

Usage

Define your custom policy and override configure method to specify what destructuring rules to use.

public class ApplicationFluentDestructuringPolicy : FluentDestructuringPolicy
{
    protected override void Configure(FluentDestructuringBuilder builder)
    {
        // Your configurations.
    }
}

Modify logger configuration.

var cfg = new LoggerConfiguration()
    .Destructure.WithFluentDestructuringPolicy<ApplicationFluentDestructuringPolicy>()
    ...

Destructuring rules applying.

Add configuration for specific entity type right here.

public class ApplicationFluentDestructuringPolicy : FluentDestructuringPolicy
{
    protected override void Configure(FluentDestructuringBuilder builder)
    {
        builder.Entity<UserRegisterRequest>(e => 
        {
            e.Property(p => p.Email)
                .Mask();
            
            e.Property(p => p.Password)
                .Ignore();
        });
    }
}

Apply predefined configuration for a specific entity.

public class UserRegisterRequestDestructuringConfiguration : IEntityDestructuringConfiguration<UserRegisterRequest>
{
    public void Configure(EntityDestructuringBuilder<UserRegisterRequest> builder)
    {
        builder.Property(p => p.Email)
            .Mask();
            
        builder.Property(p => p.Password)
            .Ignore();
    }
}

public class ApplicationFluentDestructuringPolicy : FluentDestructuringPolicy
{
    protected override void Configure(FluentDestructuringBuilder builder)
    {
        builder.ApplyConfiguration(new UserRegisterRequestDestructuringConfiguration());
    }
}

Apply all entity destructuring configurations found in a specified assembly.

public class ApplicationFluentDestructuringPolicy : FluentDestructuringPolicy
{
    protected override void Configure(FluentDestructuringBuilder builder)
    {
        builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
    }
}

1. Changing a property name.

Apply by calling WithAlias method.

builder.Entity<UserRegisterRequest>(e => 
{
    e.Property(p => p.Email)
        .WithAlias("user_email");
});

You can also use custom property name along with a main destructuring rule.

builder.Entity<UserRegisterRequest>(e => 
{
    e.Property(p => p.Email)
        .Mask()
        .WithAlias("user_email");
});

2. Ignoring a property.

Apply by calling Ignore method.

builder.Entity<UserRegisterRequest>(e => 
{
    e.Property(p => p.Password)
        .Ignore();
});

3. Logging types and properties as scalars.

Apply by calling AsScalar method.

// Whole entity.
builder.Entity<UserRegisterRequest>(e => e.AsScalar());

builder.Entity<UserRegisterRequest>(e => 
{
    // Individual property.
    e.Property(p => p.Passport)
        .AsScalar();
});

4. Masking a property.

Apply by calling Mask method.

Note that masking works for properties of type string, IEnumerable<string> or derived from it, for example, string[] or List<string>.

4.1. Default behaviour.
  • MaskCharacter: The character used for masking. The default is an asterisk *.
  • MaskLength: The length of the mask to be applied. This is the number of MaskCharacter that will be used to obfuscate the value. The default is 10.
  • PreserveValueLength: Value indicating whether the length of the original value should be preserved when applying the mask. If true, the masked value will have the same length as the original value, and the MaskLength property will be ignored. The default is false.
builder.Entity<UserRegisterRequest>(e => 
{
    // Default masking processor with default options.
    e.Property(p => p.Email)
        .Mask();
    
    // Customize default masking processor behaviour by specify options.
    e.Property(e => e.Password)
       .Mask(new DefaultMaskingProcessorOptions { PreserveValueLength = true, MaskCharacter = '#' })
});
4.2. Custom behaviour.

You can use custom masking processor by implementing the IMaskingProcessor interface and passing an instance to one of the overloads of Mask method.

public class PasswordMaskingProcessor : IMaskingProcessor
{
    public bool TryMask(string value, out string? maskedValue)
    {
        // Your implementation.
    }
}
builder.Entity<UserRegisterRequest>(e => 
{
    e.Property(e => e.Password)
       .Mask(new PasswordMaskingProcessor());
});

5. Conditional property destructuring.

You can define the condition under which the destructuring rule will be applied.

builder.Entity<UserRegisterRequest>(e => 
{
    // One of predefined conditions.
    e.Property(p => p.Email)
        .Ignore()
        .ApplyWhenNull();
    
    e.Property(e => e.Passport)
       .AsScalar()
       .WithAlias("user_passport")
       .ApplyWhenNotNull();
    
    
    // Define your custom condition.
    e.Property(p => p.Password)
        .Mask()
        .ApplyWhen(e => !string.IsNullOrWhiteSpace(e.Email) && e.Email.EndsWith("@gmail.com"));
});

6. Inner entities.

Only single-level properties are supported.

builder.Entity<UserRegisterRequest>(e => 
{
    // Will throw an exception.  
    e.Property(e => e.Passport.Series)
       .Mask();
});

Configure inner entities by calling InnerEntity method.

builder.Entity<UserRegisterRequest>(e => 
{  
    e.InnerEntity(o => o.Passport, x =>
    {
        x.Property(a => a.Series)
            .Mask();

        x.Property(a => a.Number)
            .Ignore()
            .ApplyWhenNull();
    })
    .WithAlias("user_passport")
    .ApplyWhen(e => !string.IsNullOrWhiteSpace(e.Email));
});

Or apply predefined configuration.

public class UserPassportRequestDestructuringConfiguration : IEntityDestructuringConfiguration<UserPassportRequest>
{
    public void Configure(EntityDestructuringBuilder<UserPassportRequest> builder)
    {
        builder.Property(a => a.Series)
            .Mask();

        builder.Property(a => a.Number)
            .Ignore()
            .ApplyWhenNull();
    }
}

builder.Entity<UserRegisterRequest>(e => 
{  
    e.InnerEntity(o => o.Passport, new UserPassportRequestDestructuringConfiguration())
        .WithAlias("user_passport")
        .ApplyWhen(e => !string.IsNullOrWhiteSpace(e.Email));
});

7. Global options.

  • IgnoreNullProperties - Indicating whether properties with null values should be ignored during destructuring. The default is false.
  • ExcludeTypeTag - Indicating whether the $type tag should be excluded from the destructured output. The default is false.
var cfg = new LoggerConfiguration()
    .Destructure.WithFluentDestructuringPolicy<ApplicationFluentDestructuringPolicy>(e => 
    {
        e.IgnoreNullProperties = true;
        e.ExcludeTypeTag = true;
    })
    ...
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 156 1/15/2025
1.0.0 143 9/1/2024