Skip to content

Commit 2ab9203

Browse files
Output MSBuild errors when publishing (#7566)
## Summary of changes We saw the following error in our CI: ``` 01:59:31 [INF] > "C:\Program Files\dotnet\dotnet.exe" publish c:\mnt\tracer\src\Datadog.Trace.MSBuild\Datadog.Trace.MSBuild.csproj --configuration Release --framework net461 --no-restore --no-build --output c:\mnt\shared\bin\monitoring-home\net461 /property:Platform=AnyCPU 01:59:34 [ERR] MSBUILD : error MSB4166: Child node "3" exited prematurely. Shutting down. Diagnostic information may be found in files in "C:\Users\ContainerAdministrator\AppData\Local\Temp\MSBuildTemp\" and will be named MSBuild_*.failure.txt. This location can be changed by setting the MSBUILDDEBUGPATH environment variable to a different directory. 01:59:34 [ERR] Target PublishManagedTracer has thrown an exception ``` In order to diagnose the actual error generated from MSBUILD, we are checking for these MSBuild_*.failure.txt files and printing them into the logs. Potentially, these logs could be generated in any MSBUILD call. Since we have only seen this in PublishManagedTracer, in this PR we are only checking for error files in that task, but it could easily be added to any other compilation or publishing task. ## Reason for change ## Implementation details ## Test coverage We can force an intentional crash by using this target file and using these properties: /p:CrashDuringBuild=true /p:CustomBeforeMicrosoftCommonTargets="Crash.targets" ``` <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <UsingTask TaskName="CrashNow" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"> <Task> <Using Namespace="System" /> <Code Type="Fragment" Language="cs"><![CDATA[ Environment.FailFast("Intentional crash for MSBuild failure-file test"); return true; // not reached ]]></Code> </Task> </UsingTask> <!-- Fire before Build/Publish, but only when asked AND only for the target project --> <Target Name="CrashIfEnabled" BeforeTargets="Build;Publish;CoreCompile" Condition="'$(CrashDuringBuild)'=='true' and '$(MSBuildProjectName)'=='Datadog.Trace'"> <Message Text="Crashing MSBuild worker for $(MSBuildProjectName)..." Importance="high" /> <CrashNow /> </Target> </Project> ``` ## Other details <!-- Fixes #{issue} --> <!-- ⚠️ Note: Where possible, please obtain 2 approvals prior to merging. Unless CODEOWNERS specifies otherwise, for external teams it is typically best to have one review from a team member, and one review from apm-dotnet. Trivial changes do not require 2 reviews. MergeQueue is NOT enabled in this repository. If you have write access to the repo, the PR has 1-2 approvals (see above), and all of the required checks have passed, you can use the Squash and Merge button to merge the PR. If you don't have write access, or you need help, reach out in the #apm-dotnet channel in Slack. --> --------- Co-authored-by: Andrew Lock <[email protected]>
1 parent bef226e commit 2ab9203

File tree

2 files changed

+82
-11
lines changed

2 files changed

+82
-11
lines changed

tracer/build/_build/Build.Steps.cs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ partial class Build
5252
AbsolutePath WindowsSymbolsZip => ArtifactsDirectory / "windows-native-symbols.zip";
5353
AbsolutePath OsxTracerHomeZip => ArtifactsDirectory / "macOS-tracer-home.zip";
5454
AbsolutePath BuildDataDirectory => BuildArtifactsDirectory / "build_data";
55+
AbsolutePath MsbuildDebugPath => TestLogsDirectory / "msbuild";
5556
AbsolutePath TestLogsDirectory => BuildDataDirectory / "logs";
5657
AbsolutePath ToolSourceDirectory => ToolSource ?? (OutputDirectory / "runnerTool");
5758
AbsolutePath ToolInstallDirectory => ToolDestination ?? (ToolSourceDirectory / "install");
@@ -794,17 +795,27 @@ async Task DownloadWafVersion(string libddwafVersion = null, string uncompressFo
794795
? TargetFrameworks
795796
: TargetFrameworks.Where(framework => !framework.ToString().StartsWith("net4"));
796797

797-
// Publish Datadog.Trace.MSBuild which includes Datadog.Trace
798-
DotNetPublish(s => s
799-
.SetProject(Solution.GetProject(Projects.DatadogTraceMsBuild))
800-
.SetConfiguration(BuildConfiguration)
801-
.SetTargetPlatformAnyCPU()
802-
.EnableNoBuild()
803-
.EnableNoRestore()
804-
.CombineWith(targetFrameworks, (p, framework) => p
805-
.SetFramework(framework)
806-
.SetOutput(MonitoringHomeDirectory / framework))
807-
);
798+
try
799+
{
800+
// Publish Datadog.Trace.MSBuild which includes Datadog.Trace
801+
DotNetPublish(s => s
802+
.SetProject(Solution.GetProject(Projects.DatadogTraceMsBuild))
803+
.SetConfiguration(BuildConfiguration)
804+
.SetTargetPlatformAnyCPU()
805+
.EnableNoBuild()
806+
.EnableNoRestore()
807+
.CombineWith(targetFrameworks, (p, framework) => p
808+
.SetFramework(framework)
809+
.SetOutput(MonitoringHomeDirectory / framework)
810+
.SetProcessEnvironmentVariable("MSBUILDDEBUGPATH", MsbuildDebugPath))
811+
);
812+
}
813+
catch
814+
{
815+
// Print tail of MSBuild failure notes, if any, then rethrow
816+
MSBuildLogHelper.DumpMsBuildChildFailures(MsbuildDebugPath);
817+
throw;
818+
}
808819
});
809820

810821
Target PublishManagedTracerR2R => _ => _
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text;
6+
using Nuke.Common;
7+
using Nuke.Common.IO;
8+
9+
using Logger = Serilog.Log;
10+
11+
internal static class MSBuildLogHelper
12+
{
13+
internal static void DumpMsBuildChildFailures(string msbuildDebugPath, int tailChars = 10 * 1024, int maxFiles = 2)
14+
{
15+
try
16+
{
17+
if (!Directory.Exists(msbuildDebugPath))
18+
{
19+
Logger.Information($"No MSBuild failure directory: {msbuildDebugPath}");
20+
return;
21+
}
22+
23+
var files = Directory.EnumerateFiles(msbuildDebugPath, "MSBuild_*.failure.txt", SearchOption.AllDirectories)
24+
.OrderByDescending(File.GetLastWriteTimeUtc)
25+
.Take(maxFiles)
26+
.ToList();
27+
28+
if (files.Count == 0)
29+
{
30+
Logger.Information("No MSBuild failure notes found.");
31+
return;
32+
}
33+
34+
foreach (var file in files)
35+
{
36+
try
37+
{
38+
// Use BOM detection: handles UTF-8/UTF-16 automatically
39+
using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
40+
using var sr = new StreamReader(fs, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
41+
var text = sr.ReadToEnd();
42+
43+
var tail = text.Length > tailChars ? text[^tailChars..] : text;
44+
45+
Logger.Error($"----- BEGIN {file} (showing last {tail.Length} of {text.Length} chars) -----");
46+
Logger.Error(tail);
47+
Logger.Error("----- END -----");
48+
}
49+
catch (Exception exRead)
50+
{
51+
Logger.Warning($"Could not read {file}: {exRead.Message}");
52+
}
53+
}
54+
}
55+
catch (Exception ex)
56+
{
57+
Logger.Warning($"Failed to dump MSBuild child-node diagnostics: {ex.Message}");
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)