dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.66k stars 1.06k forks source link

`dotnet build` support export warnings/errors to json #43269

Closed WeihanLi closed 1 week ago

WeihanLi commented 1 week ago

Is your feature request related to a problem? Please describe.

When I want to do some refactoring on a legacy project, there're so many warnings, want to propose a feature that could export the build warnings/errors into a JSON so that we could analyze the warnings/errors easily and refactor according to the analyzed result

Describe the solution you'd like

Maybe a --format parameter like other commands, outputs to the console by default and could output as JSON when needed

KalleOlaviNiemitalo commented 1 week ago

The Roslyn compiler supports output to a SARIF JSON file already; see ErrorLog. Is this issue for NuGet and MSBuild diagnostics?

WeihanLi commented 1 week ago

@KalleOlaviNiemitalo thanks very much, it helps, while seemed there's only C# compile error, nuget audit warning not reported when I treat those warning as an error, but would get error when dotnet build, maybe it's better to support from dotnet build/msbuild level

image

baronfel commented 1 week ago

@WeihanLi you can do this today by writing a custom MSBuild logger and passing it to MSBuild via the --logger parameter to any 'dotnet' build invocation. This same mechanism is how Terminal Logger, Binary Logger, and all other custom loggers work. Why don't you try prototyping that and seeing if it works for you? You'd basically just need to handle warnings and errors in your logger and emit them in whatever format you like.

WeihanLi commented 1 week ago

@baronfel thanks very much for the info, finding sample from docs, would have a try, thanks again for the help

https://learn.microsoft.com/en-us/visualstudio/msbuild/build-loggers?view=vs-2022

baronfel commented 1 week ago

I'm very interested in seeing how it works for you - if you make one could you link it here?

WeihanLi commented 1 week ago

@baronfel a simple logger example, code source: https://github.com/WeihanLi/SamplesInPractice/blob/main/MSBuildLoggerSample/MSBuildJsonLogger/JsonLogger.cs

using Microsoft.Build.Framework;
using System.Text.Encodings.Web;
using System.Text.Json;

namespace MSBuildJsonLogger;

public sealed class JsonErrorLogger : ILogger
{
    private const string ErrorLogFileName = "json-error-logger.json";
    private static readonly JsonSerializerOptions JsonSerializerOptions = new()
    {
        WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
    };

    private readonly List<BuildError> _errors = new();
    public void Initialize(IEventSource eventSource)
    {
        eventSource.ErrorRaised += EventSourceOnErrorRaised;
    }

    private void EventSourceOnErrorRaised(object sender, BuildErrorEventArgs e)
    {
        _errors.Add(new BuildError(e.Subcategory, e.Code, e.File, e.LineNumber, e.ColumnNumber, e.EndLineNumber, e.EndColumnNumber, e.Message, e.HelpKeyword, e.SenderName));
    }

    public void Shutdown()
    {
        using var fs = File.Create(ErrorLogFileName);
        JsonSerializer.Serialize(fs, _errors, JsonSerializerOptions);

        _errors.Clear();
    }

    public LoggerVerbosity Verbosity { get; set; }
    public string? Parameters { get; set; }
}

public sealed record BuildError(
    string Subcategory,
    string Code,
    string File,
    int LineNumber,
    int ColumnNumber,
    int EndLineNumber,
    int EndColumnNumber,
    string? Message,
    string? HelpKeyword,
    string? SenderName);

And when to use it, use the customized logger type and assembly

dotnet build -logger:"JsonErrorLogger,C:\projects\source\SamplesInPractice\MSBuildLoggerSample\MSBuildJsonLogger\bin\Debug\net8.0\MSBuildJsonLogger.dll"

output sample:

[
  {
    "Subcategory": "",
    "Code": "CS0103",
    "File": "C:\\projects\\source\\SamplesInPractice\\SemanticKernelSamples\\GetStarted\\MemorySample.cs",
    "LineNumber": 29,
    "ColumnNumber": 9,
    "EndLineNumber": 0,
    "EndColumnNumber": 0,
    "Message": "The name 'memoryBuilder' does not exist in the current context",
    "HelpKeyword": null,
    "SenderName": "Csc"
  },
  {
    "Subcategory": "",
    "Code": "CS0103",
    "File": "C:\\projects\\source\\SamplesInPractice\\SemanticKernelSamples\\GetStarted\\MemorySample.cs",
    "LineNumber": 30,
    "ColumnNumber": 9,
    "EndLineNumber": 0,
    "EndColumnNumber": 0,
    "Message": "The name 'memoryBuilder' does not exist in the current context",
    "HelpKeyword": null,
    "SenderName": "Csc"
  },
  {
    "Subcategory": "",
    "Code": "CS0103",
    "File": "C:\\projects\\source\\SamplesInPractice\\SemanticKernelSamples\\GetStarted\\MemorySample.cs",
    "LineNumber": 34,
    "ColumnNumber": 22,
    "EndLineNumber": 0,
    "EndColumnNumber": 0,
    "Message": "The name 'memoryBuilder' does not exist in the current context",
    "HelpKeyword": null,
    "SenderName": "Csc"
  }
]
KalleOlaviNiemitalo commented 1 week ago

@WeihanLi, do you need JSON logs also for non-MSBuild operations like dotnet tool install or dotnet workload install?

WeihanLi commented 1 week ago

@KalleOlaviNiemitalo not for this, for this scenario, I only focus on the logs when dotnet build

baronfel commented 1 week ago

FWIW if we do do something here for JSON output, it likely wouldn't be SARIF by default. SARIF is a specific kind of formatted JSON, so we'd likely do something simple like this for JSON, and have a dedicated format name for SARIF separate from JSON.