Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't read .binlog file in .NET 6 Preview 2 #6225

Closed
jonathanpeppers opened this issue Mar 4, 2021 · 9 comments
Closed

Can't read .binlog file in .NET 6 Preview 2 #6225

jonathanpeppers opened this issue Mar 4, 2021 · 9 comments
Assignees
Labels
bug needs-triage Have yet to determine what bucket this goes in.

Comments

@jonathanpeppers
Copy link
Member

jonathanpeppers commented Mar 4, 2021

Issue Description

We have some integration test code that fails to read .binlog files, such as:

var duration = TimeSpan.Zero;
using var fileStream = File.OpenRead("msbuild.binlog");
using var gzip = new GZipStream(fileStream, CompressionMode.Decompress);
using var binaryReader = new BinaryReader(gzip);
int fileFormatVersion = binaryReader.ReadInt32();
var buildReader = new BuildEventArgsReader(binaryReader, fileFormatVersion);
BuildEventArgs args;
var started = new Stack<DateTime>();
while ((args = buildReader.Read()) != null)
{
	if (args is ProjectStartedEventArgs projectStarted)
	{
		started.Push(projectStarted.Timestamp);
	}
	else if (args is ProjectFinishedEventArgs projectFinished)
	{
		duration += projectFinished.Timestamp - started.Pop();
	}
}

if (duration == TimeSpan.Zero)
	throw new InvalidDataException($"No project build duration found!");

There might be a way to clean up this code (let me know), but BuildEventArgsReader.Read() returns null on the first call.

This was working in .NET 6 Preview 1.

Steps to Reproduce

Try the example project, just build & run it in VS with the right .NET 6.0.100-preview.2.21114.3 installed:

msbuild-binlog.zip

This project attempts to parse a .binlog that was produced on my machine -- it was a build of a .NET 6 Android application. Both the sample project above and .binlog were using the same .NET version.

Expected Behavior

BuildEventArgsReader.Read() returns something.

Actual Behavior

BuildEventArgsReader.Read() returns null.

Versions & Configurations

Windows 10, using .NET 6.0.100-preview.2.21114.3

Installed from: https://dotnetcli.azureedge.net/dotnet/Sdk/6.0.100-preview.2.21114.3/dotnet-sdk-6.0.100-preview.2.21114.3-win-x64.exe

Attach a binlog

See the .zip above.

@jonathanpeppers jonathanpeppers added bug needs-triage Have yet to determine what bucket this goes in. labels Mar 4, 2021
jonathanpeppers added a commit to radekdoulik/xamarin-android that referenced this issue Mar 4, 2021
@KirillOsenkov KirillOsenkov self-assigned this Mar 6, 2021
@KirillOsenkov
Copy link
Member

KirillOsenkov commented Mar 6, 2021

The version of the binlog file format has increased, so older MSBuild can't read it anymore.

There are a couple of ways to fix this. You can look into using MSBuildLocator (https://github.com/microsoft/msbuildlocator) to load the latest MSBuild binaries at runtime that support this format. It's a bit tricky, see here for a sample:
#3434 (comment)

Alternatively, you can switch to the MSBuild.StructuredLogger NuGet package, https://www.nuget.org/packages/MSBuild.StructuredLogger. It has a copy of BuildEventArgsReader that is up-to-date with the latest. Maybe easier than using MSBuild for this scenario. I recommend this:

  <ItemGroup>
    <PackageReference Include="MSBuild.StructuredLogger" Version="2.1.303" />
  </ItemGroup>
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging.StructuredLogger;

namespace msbuild_binlog
{
	class Program
	{
		static void Main()
		{
			var reader = new BinLogReader();
			var records = reader.ReadRecords("msbuild.binlog");

			TimeSpan duration = TimeSpan.Zero;
			var started = new Stack<DateTime>();
			foreach (var record in records)
			{
				if (record.Args is ProjectStartedEventArgs projectStarted)
				{
					started.Push(projectStarted.Timestamp);
				}
				else if (record.Args is ProjectFinishedEventArgs projectFinished)
				{
					duration += projectFinished.Timestamp - started.Pop();
				}
			}

			if (duration == TimeSpan.Zero)
				throw new InvalidDataException($"No project build duration found!");

			Console.WriteLine(duration);
		}
	}
}

@KirillOsenkov
Copy link
Member

KirillOsenkov commented Mar 6, 2021

Actually here's a better way to do it:

using System;
using System.IO;
using System.Linq;
using Microsoft.Build.Logging.StructuredLogger;

namespace msbuild_binlog
{
	class Program
	{
		static void Main()
		{
			var build = BinaryLog.ReadBuild("msbuild.binlog");
			var duration = build
				.FindChildrenRecursive<Project>()
				.Aggregate(TimeSpan.Zero, (duration, project) => duration + project.Duration);

			if (duration == TimeSpan.Zero)
				throw new InvalidDataException($"No project build duration found!");

			Console.WriteLine(duration);
		}
	}
}

This way the library will pair up starts and finishes for multi-core builds correctly (you can have mismatched project started for projects building on different nodes).

jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Mar 8, 2021
Context: dotnet/msbuild#6225
Context: https://www.nuget.org/packages/MSBuild.StructuredLogger/

In .NET 6 Preview 2, the `.binlog` file format version increased. This
means we can no longer use the latest MSBuild NuGet packages to parse
these files. 16.9.0 isn't recent enough:

https://www.nuget.org/packages/Microsoft.Build/16.9.0

Instead, we can use the MSBuild.StructuredLogger package used by the
[MSBuild binlog viewer](msbuildlog.com), as it is able to read the new
`.binlog` format. It also is quite a bit less code to do what we need.

Going forward, this package should be the best for parsing `.binlog`
files when using .NET 6 Preview builds.
@jonathanpeppers
Copy link
Member Author

Ok, to summarize, the 16.9.0 Microsoft.Build.* packages on NuGet are not new enough to parse the new .binlog format.

Thanks for the example above, it's working for us, thanks!

@KirillOsenkov
Copy link
Member

Yes, binlog format is actively changing between 16.9 and 16.10 so you may need to keep bumping MSBuild.StructuredLogger NuGet if this breaks again

jonpryor pushed a commit to dotnet/android that referenced this issue Mar 8, 2021
Context: dotnet/msbuild#6225
Context: https://www.nuget.org/packages/MSBuild.StructuredLogger/
Context: 8cd0b47

Commit 8cd0b47 updated the xamarin-android build environment to use
.NET 6 Preview 2, and had to disable many of the
`Xamarin.Android.Build.Tests.PerformanceTest` integration tests as
.NET 6 Preview 2 updated the `.binlog` version format in an
incompatible manner.  This meant that we couldn't parse the files,
which meant we couldn't properly extract timestamps.

Instead, we can use the [MSBuild.StructuredLogger][0] NuGet package,
used by the [MSBuild binlog viewer][1], as it is able to read the new
`.binlog` format.  It also is quite a bit less code to do what we need.

Going forward, this package should be the best for parsing `.binlog`
files when using .NET 6 Preview builds.

[0]: https://www.nuget.org/packages/MSBuild.StructuredLogger
[1]: https://msbuildlog.com
@jonathanpeppers
Copy link
Member Author

FYI @KirillOsenkov I'm seeing a new one on .NET 6 Preview 3:

System.NotSupportedException : Unsupported log file format. Latest supported version is 10, the log file has version 11.

So we must already need a new MSBuild.StructuredLogger, thanks!

@KirillOsenkov
Copy link
Member

Yes, and I'm working on a PR that will further bump the version to 12, just to keep you on your toes!

@KirillOsenkov
Copy link
Member

btw would love to see build duration comparison and binlog size comparison between .NET 5 and .NET 6 previews for your codebase!

@jonathanpeppers
Copy link
Member Author

I don't know that we will have .NET 5 to compare against -- we are still partially using msbuild (not fully using dotnet build) to build xamarin/xamarin-android. We have logs of small test app projects, but that might be it.

We could certainly compare building dotnet/maui with .NET 6 preview 1 vs newer previews, though.

@KirillOsenkov
Copy link
Member

Nah, that’s fine. Just thought if you had a history of binlogs readily available from CI, but no biggie.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug needs-triage Have yet to determine what bucket this goes in.
Projects
None yet
Development

No branches or pull requests

2 participants