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:

ILogger logger = ...;

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

In one of my projects, I need to store logs in Elasticsearch and query them using some parameters. While it's technically possible to index a field where the values are of different types, it creates complexity (Stack Overflow answer). As the project grew, more and more log messages were added. This means that all the time you log a structured log message, you need to ensure that the parameters are of the expected types.

To help with this, I created a Roslyn analyzer that checks the types of parameters of structured log messages at compile time. First, you need to install the analyzer:

dotnet add package Meziantou.Analyzer

To configure the rule, you need to 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:

# A property named {Name} should be of type string

# A property named {Count} should be of type int or long

# A property named {Length} should be of type int? (nullable int)

Then, you need to add the file to the AdditionalFiles collection in the .csproj file:

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

Then, the analyzer reports log parameters of the wrong type:

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");

If you want to be sure all log parameters are configured, you can enable the opt-in rule MA0135 by adding a .editorconfig file:

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?Buy Me A Coffee💖 Sponsor on GitHub