Stop using diagnostic verbosity in MSBuild

 
 
  • Gérald Barré

On CI, some projects use the msbuild diagnostic verbosity to get more information about the build. This is useful to troubleshoot build issues. However, this verbosity level has some drawbacks. In this post, I describe how to use the binary log feature of MSBuild to get the same information in a more efficient way.

#Diagnostic verbosity vs binary log

The msbuild diagnostic verbosity is the most verbose level of verbosity. It outputs a lot of information about the build process, such as the list of all the targets executed, the properties and items used, and the tasks executed. This information is useful when you need to troubleshoot a build issue, but it has some drawbacks:

  • Output is hard to read because of the amount of information.
  • The build time is slower because of the amount of information written to the console. The more projects the solution has, the slower the build will be.

To get the same information in a more efficient way, you can use the binary log feature of MSBuild. The binary log is a file that contains all the information about the build process in a structured format. You can use the MSBuildStructuredLog tool to read the binary log and get the same information as the msbuild diagnostic verbosity, but in a more readable and efficient way. The binlog has many advantages over the diagnostic verbosity:

  • The binlog is a structured file that can be easily read by tools, making it easier to search for information
  • The binlog is much smaller than the diagnostic verbosity output
  • The impact on the build time is much smaller than the diagnostic verbosity
  • The binlog can embed additional files, making it easier to investigate build issues
  • The binlog can be replayed to get the same output as the diagnostic verbosity
  • The binlog format is documented and a NuGet library is available to read binlog files (example)

Here's a small benchmark to compare the build time and the output size of the diagnostic verbosity and the binary log:

Build time (on a modest machine such as the GitHub Hosted runner):

  • Mesaure-Command { dotnet build --no-incremental --disable-build-servers --verbosity diagnostic }
  • Mesaure-Command { dotnet build --no-incremental --disable-build-servers /bl }
ProjectDiagnostic verbosityBinary log
dotnet new console2.082s1.962s
Meziantou.Analyzer37s32s
Meziantou.Framework4.17m3.16m

Output Size:

ProjectOutput size
Meziantou.Framework (default verbosity)54kB
Meziantou.Framework (diagnostic verbosity)1.68GB
Meziantou.Framework (binary log)22MB

While the diagnostic log contains lot of information, I'm not sure I want to search something in a 1.68GB file!

#Generating a binary log

To generate a binary log, you can use the /bl switch:

Shell
msbuild.exe MySolution.sln /bl
msbuild.exe MySolution.sln /bl:out.binlog

If you really want to read text, you can regenerate the diagnostic log from the binary log:

Shell
msbuild.exe msbuild.binlog /noconlog /flp:v=diag;logfile=diag.log
dotnet msbuild output.binlog /noconlog "/flp:v=diag;logfile=diag.log"

Note that you can also embed custom files in the binary log, so you can easily investigate the build process. By default all MSBuild files (csproj, props, targets) are embedded in the binary log. You can also embed additional files using the Embed metadata (more info):

XML
<Project Sdk="Microsoft.NET.Sdk">
  <ItemGroup>
    <EmbedInBinlog Include="**/*.txt" />
  </ItemGroup>
</Project>

#Exploring the binary log

To read the binary log, you can use the MSBuildStructuredLog tool. You can install it using the following command:

Shell
winget install KirillOsenkov.MSBuildStructuredLogViewer

MSBuildStructuredLog provides a search syntax to find information in the log. For example, you can search for a specific target, task, or message. You can also filter the log to display only the information you are interested in.

MSBuildStructuredLogViewerMSBuildStructuredLogViewer

The interface provides some useful data such as:

  • Search panel to find targets, tasks, messages, items, etc. (search syntax documentation)
  • A tree view to navigate the log
  • A timeline to see the duration of each task
  • An analyzer and source generator summary (execution time per analyzer or source generator)

#Generating the binary log in GitHub Actions

You can easily integrate the binary log in your CI pipeline. For example, with GitHub Actions:

YAML
name: publish
on:
  push:
    branches:
      - 'main'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET Core
        uses: actions/setup-dotnet@v4

      - run: dotnet build /bl:build.binlog

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: binlog
          if-no-files-found: error
          retention-days: 3
          path: '**/*.binlog'

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