Analyzer to validate the parameters of structured log messages

 
 
  • Gérald Barré

Microsoft.Extensions.Logging allows providers to implement semantic or structured logging. This means that the logging system can store the parameters of the log message as fields instead of just storing the formatted message. This enables logging providers to index the log parameters and perform ad-hoc queries on them.

If you are not familiar with structured logging, here's an example of a structured log message with two parameters:

C#
ILogger logger = ...;

logger.LogInformation("Get values for user {Name} with {Id}", "Meziantou", 123);

In one of my projects, I store logs in Elasticsearch and query them by parameter values. While indexing a field with mixed value types is technically possible, it adds complexity (Stack Overflow answer). As the project grew and more log messages were added, I needed a reliable way to ensure log parameters always use the expected types.

To address this, I created a Roslyn analyzer that validates parameter types of structured log messages at compile time. First, install the analyzer:

Shell
dotnet add package Meziantou.Analyzer

To configure the rule, create a file named LoggerParameterTypes.txt or LoggerParameterTypes.*.txt.

  • Each line is of the form PropertyName;ExpectedType1;ExpectedType2;ExpectedType3;...
  • A type is represented by its CLR metadata name or XML Comment ID
  • Lines starting with # are comments

Here's an example configuration file:

LoggerParameterTypes.txt
# A property named {Name} should be of type string
Name;System.String

# A property named {Count} should be of type int or long
Count;System.Int32;System.Int64

# A property named {Length} should be of type int? (nullable int)
Length;System.Nullable{System.Int32}

Next, add the file to the AdditionalFiles collection in your .csproj:

XML
<Project Sdk="Microsoft.NET.Sdk">
  <ItemGroup>
    <AdditionalFiles Include="$(MSBuildThisFileDirectory)\LoggerParameterTypes.txt" />
  </ItemGroup>
</Project>

The analyzer then reports any log parameters with incorrect types:

C#
using Microsoft.Extensions.Logging;

ILogger logger = ...;

// report MA0124 because the configuration file indicates {Name} should be
// of type String but the provided value is a Int32
logger.LogInformation("{Name}", 123);

// Ok as "Meziantou" is a string
logger.LogInformation("{Name}", "Meziantou");

To ensure all log parameters are configured, enable the opt-in rule MA0135 by adding a .editorconfig file:

.editorconfig
[*.cs]
dotnet_diagnostic.MA0135.severity = warning

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?