Structured Logging with Sensitive Data Sanitization using Serilog

Introduction

Logging is an essential aspect of application development, offering insights into application behavior and performance. However, logging sensitive data like passwords or personal information can pose security risks. In this blog post, we'll delve into implementing structured logging with Serilog and sanitizing sensitive data before logging it, utilizing the Console sink as an example.

Overview of Structured Logging

Structured logging entails logging data in a structured format, typically as key-value pairs. This format enhances searchability, filtering, and analysis of log data compared to traditional plain text logging.

The source code can be downloaded from GitHub

Introduction to Serilog

Serilog is a popular logging library for .NET, supporting structured logging out of the box. It offers a versatile configuration API and various sinks for directing log data to different destinations.

Setting up Serilog with Console Sink

The Console sink is a straightforward sink provided by Serilog for logging to the console. It is commonly used during development or debugging. Setting up Serilog with the Console sink requires minimal configuration.

Install packages Serilog and Serilog.Sinks.Console

using Serilog;

Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .CreateLogger();

Log.Information("Hello, structured logging!");

Log.CloseAndFlush();

Sanitizing Sensitive Data

Sensitive data, such as passwords or personal information, should not be logged in plain text to prevent exposure. We can use Serilog's Destructure.UsingAttributes() method to sanitize sensitive data before logging it.

Configure the sanitization

Install the package: Destructurama. Attributed

using Destructurama;
using Serilog;

Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
.Destructure.UsingAttributes()            //.Destructure.ByTransforming<object>(LogSanitizer.SanitizeSensitiveData)
            .CreateLogger();

Structured Logging Example

Let's demonstrate implementing structured logging with Serilog and sensitive data sanitization.

using Destructurama.Attributed;

namespace SanitizeLogData
{
    public class SensitiveData
    {

        [NotLogged]
        public string Password { get; set; }
        public string Username { get; set; }
        public Address Address { get; set; }

    }

    public class Address
    {
        public string Street { get; set; }       
        public string ZipCode { get; set; }
    }
        

       
}

Add the attribute [NotLogged] on the properties that need to be excluded while logging.

using Destructurama;
using SanitizeLogData;
using Serilog;

Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .Destructure.UsingAttributes()
            //.Destructure.ByTransforming<object>(LogSanitizer.SanitizeSensitiveData)
            .CreateLogger();

var sensitiveData = new SensitiveData
{
    Username = "praveendran",
    Password = "supersecret",
    Address = new Address
    {
        Street = "123 Main St",
        ZipCode = "12345"
    }
};

Log.Information("Sensitive data: {@SensitiveData}", sensitiveData);

Log.CloseAndFlush();

Execute the console, you can see the below output where password property has been excluded from the log.

Console

This approach ensures that the sensitive data is properly sanitized(excluded) before being logged, regardless of the Serilog configuration