Skip to content

Microsoft.Extensions.Logging.Console logs an unnecessary Message node in a Scopes node #85514

@bartlomiejgawel

Description

@bartlomiejgawel

Description

Consider the following code:

var serviceProvider = new ServiceCollection()
    .AddLogging(options =>
    {
        options.AddJsonConsole(jsonOptions =>
        {
            jsonOptions.IncludeScopes = true;
            jsonOptions.JsonWriterOptions = new JsonWriterOptions { Indented = true };
        });
    })
    .BuildServiceProvider();

var logger = serviceProvider.GetRequiredService<ILogger<Program>>();

using (logger.BeginScope(new Dictionary<string, object> { ["Id"] = "Value" }))
{
    logger.LogInformation("Test");
}

You want to add an additional property by using the BeginScope method. It works but it also adds an unnecessary node Message for no reason:

{
  "EventId": 0,
  "LogLevel": "Information",
  "Category": "Program",
  "Message": "Test",
  "State": {
    "Message": "Test",
    "{OriginalFormat}": "Test"
  },
  "Scopes": [
    {
      "Message": "System.Collections.Generic.Dictionary\u00602[System.String,System.Object]",
      "Id": "Value"
    }
  ]
}

It would be nice to either remove that Message node or add a flag to remove it:
https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs#L111

Reproduction Steps

You can test it here or by running the following code:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Text.Json;

public class Program
{
    public static void Main()
    {
        var serviceProvider = new ServiceCollection()
            .AddLogging(options =>
            {
                options.AddJsonConsole(jsonOptions =>
                {
                    jsonOptions.IncludeScopes = true;
                    jsonOptions.JsonWriterOptions = new JsonWriterOptions { Indented = true };
                });
            })
            .BuildServiceProvider();

        var logger = serviceProvider.GetRequiredService<ILogger<Program>>();

        using (logger.BeginScope(new Dictionary<string, object> { ["Id"] = "Value" }))
        {
            logger.LogInformation("Test");
        }
    }
}

Expected behavior

It would be nice to have the following output:

{
  "EventId": 0,
  "LogLevel": "Information",
  "Category": "Program",
  "Message": "Test",
  "State": {
    "Message": "Test",
    "{OriginalFormat}": "Test"
  },
  "Scopes": [
    {
      "Id": "Value"
    }
  ]
}

Actual behavior

Currently, it prints the following result:

{
  "EventId": 0,
  "LogLevel": "Information",
  "Category": "Program",
  "Message": "Test",
  "State": {
    "Message": "Test",
    "{OriginalFormat}": "Test"
  },
  "Scopes": [
    {
      "Message": "System.Collections.Generic.Dictionary\u00602[System.String,System.Object]",
      "Id": "Value"
    }
  ]
}

Regression?

No

Known Workarounds

No response

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions