New structured log output for Apple and Android platforms#1579
Merged
matouskozak merged 7 commits intodotnet:mainfrom Apr 2, 2026
Merged
New structured log output for Apple and Android platforms#1579matouskozak merged 7 commits intodotnet:mainfrom
matouskozak merged 7 commits intodotnet:mainfrom
Conversation
Add structured Android run summaries and filter logcat output
There was a problem hiding this comment.
Pull request overview
Adds a shared, structured “run summary” output at the end of Apple and Android runs to make Helix investigations and automated parsing easier, while also reducing Android console noise by filtering logcat output.
Changes:
- Introduces
RunSummaryEmitter(Common) to emit a JSON result block delimited by<<XHARNESS_RESULT_START>>/<<XHARNESS_RESULT_END>>and writexharness-result.json. - Extends diagnostics infrastructure with
DiagnosticsFile+IDiagnosticsData.Filesto track produced artifacts. - Updates Android (
InstrumentationRunner,AdbRunner) and Apple (BaseOrchestrator,TestOrchestrator) to emit summaries and improve log handling; adds targeted unit tests.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Microsoft.DotNet.XHarness.Apple.Tests/Orchestration/CopyLogsToMainLogTests.cs | New tests validating which Apple logs get copied into the main log (simulator/device vs MacCatalyst). |
| tests/Microsoft.DotNet.XHarness.Android.Tests/InstrumentationRunnerSummaryTests.cs | New tests validating JSON summary emission content (exit code, platform, device info, files, Helix URLs). |
| tests/Microsoft.DotNet.XHarness.Android.Tests/AdbRunnerLogFilterTests.cs | New tests validating logcat filtering to DOTNET-tagged lines. |
| src/Microsoft.DotNet.XHarness.Common/RunSummaryEmitter.cs | New shared emitter for structured JSON result block + file output. |
| src/Microsoft.DotNet.XHarness.Common/CommandDiagnostics.cs | Adds DiagnosticsFile model and IDiagnosticsData.Files to track produced files. |
| src/Microsoft.DotNet.XHarness.Apple/Orchestration/TestOrchestrator.cs | Copies the appropriate log type into the main log (ApplicationLog generally; SystemLog for MacCatalyst). |
| src/Microsoft.DotNet.XHarness.Apple/Orchestration/BaseOrchestrator.cs | Ensures Apple run summary emission happens (finally) and collects file-backed logs into the summary. |
| src/Microsoft.DotNet.XHarness.Android/InstrumentationRunner.cs | Tracks produced files and emits Android run summary + writes xharness-result.json. |
| src/Microsoft.DotNet.XHarness.Android/AdbRunner.cs | Filters console logcat output to DOTNET-tagged lines while keeping the full log in a file. |
Comments suppressed due to low confidence (1)
src/Microsoft.DotNet.XHarness.Android/InstrumentationRunner.cs:222
PullResultXMLsreturns a value that is assigned tofailurePullingFiles, but the local variable is namedsuccessand is set totruein the exception path. This makes the control flow hard to reason about and easy to break in future edits. Rename the local to reflect what it actually represents (e.g.,failurePullingFiles) and keep the return semantics consistent.
private bool PullResultXMLs(string apkPackageName, string outputDirectory, IReadOnlyDictionary<string, string> resultValues, List<DiagnosticsFile> producedFiles)
{
bool success = false;
foreach (string possibleResultKey in s_xmlOutputVariableNames)
{
if (!resultValues.TryGetValue(possibleResultKey, out string? resultFile))
{
continue;
}
_logger.LogInformation($"Found XML result file: '{resultFile}'(key: {possibleResultKey})");
try
{
_runner.PullFiles(apkPackageName, resultFile, outputDirectory);
producedFiles.Add(new DiagnosticsFile
{
Name = Path.GetFileName(resultFile),
Type = "test-results",
Path = Path.Combine(outputDirectory, Path.GetFileName(resultFile)),
});
}
catch (Exception toLog)
{
_logger.LogError(toLog, "Hit error (typically permissions) trying to pull {filePathOnDevice}", resultFile);
success = true;
}
}
return success;
}
vitek-karas
approved these changes
Apr 2, 2026
Member
vitek-karas
left a comment
There was a problem hiding this comment.
Looks great - I didn't look at the code in detail, just the overall design and ideas though.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When investigating test failures in Helix, the XHarness console output lacked a consistent, structured summary of what happened during a run. Key information — exit codes, device details, produced files, and Helix URLs — was scattered across verbose log output, making it difficult for both humans and automated tooling to quickly parse results.
Additionally, Android logcat output was dumped in its entirety to the console log, burying the relevant DOTNET-tagged entries in thousands of lines of system noise.
Changes
New:
RunSummaryEmitter(shared by both platforms)Introduces a unified
RunSummaryEmitterinMicrosoft.DotNet.XHarness.Commonthat emits a structured JSON block delimited by<<XHARNESS_RESULT_START>>/<<XHARNESS_RESULT_END>>markers at the end of every run. The JSON contains:Both Android and Apple platforms use this shared emitter, ensuring consistent output across all run types.
Android improvements
DOTNET-tagged logcat lines (the full unfiltered log is still written to the output file)InstrumentationRunnertracks all produced files (test results XMLs, logcat, bugreport) viaDiagnosticsFileand includes them in the summaryarm64-v8a,x86)Apple improvements
CopyLogsToMainLogrefactor: Now runs for all targets including simulators (previously skipped). MacCatalyst correctly copiesSystemLoginstead ofApplicationLogsince MacCatalyst apps run as native macOS processesBaseOrchestratorcollects all file-backed logs into the diagnostics summary with their types (executionlog, testlog, systemlog, applicationlog, xmllog, etc.)Common infrastructure
DiagnosticsFilemodel inCommandDiagnostics.csfor tracking produced filesIDiagnosticsData.Filesproperty added for file manifest supportxharness-result.jsonwritten to output directory for downstream toolingExample output
Android device:
Apple iOS simulator:
Testing
AdbRunnerLogFilterTests— validates DOTNET line filtering from logcat outputInstrumentationRunnerSummaryTests— validates Android file tracking and JSON summary emissionCopyLogsToMainLogTests— validates Apple log copying behavior for simulators, devices, and MacCatalyst