Skip to content

Fix TerminalLogger auto-detection under MSBuild Server on Unix - #14077

Merged
JanProvaznik merged 2 commits into
dotnet:mainfrom
JanProvaznik:tl-auto-server-unix
Jun 17, 2026
Merged

JanProvaznik merged 2 commits into
dotnet:mainfrom
JanProvaznik:tl-auto-server-unix

Conversation

@JanProvaznik

Copy link
Copy Markdown
Member

Fixes #13940

Context

With MSBuild Server enabled (MSBUILDUSESERVER=1 / DOTNET_CLI_USE_MSBUILD_SERVER=true), -tl:auto (and the default) does not select TerminalLogger even from a real interactive terminal — it falls back to the classic console logger. The same invocation with the server disabled selects TL correctly. Reproduces on Unix (macOS/Linux); on Windows the inverse mis-detection happens (TL stays on under msbuild > file.txt).

Root cause: TerminalLogger auto-detection runs in XMake.ProcessTerminalLoggerConfiguration, which under the server executes in the server node. NativeMethods.QueryIsScreenAndTryEnableAnsiColorCodes() inspects the current process's Console, but the node's stdout is a redirected pipe, so the decision uses the node's console state instead of the client's. The client already captures the real terminal's capabilities into a TargetConsoleConfiguration and transmits them (stored as ConsoleConfiguration.Provider), but the query never consulted it.

Changes

  • src/Framework/NativeMethods.cs — add ConsoleConfigurationOverride. When set, QueryIsScreenAndTryEnableAnsiColorCodes returns the client's transmitted screen/ANSI capabilities and null for the original console mode (the node must not change/restore its own console).
  • src/Build/BackEnd/Node/OutOfProcServerNode.cs — set the override from command.ConsoleConfiguration alongside ConsoleConfiguration.Provider, and clear it in a finally.

This is a single shared seam: XMake, TerminalLogger.CreateTerminalOrConsoleLogger*, and SimpleErrorLogger all call the query and become correct under the server with no further changes. In-proc builds are unaffected (override is null). It also corrects the Windows > file.txt case.

The override is set unconditionally from each build's own transmitted configuration before the build reads it, so a long-lived, reused server node never observes stale state across builds.

No ChangeWave: this is a correctness fix that aligns server behavior with the non-server (and documented default-TL) behavior, in an already opt-in scenario, with no new warnings/errors.

Testing

  • src/Framework.UnitTests/NativeMethods_Tests.cs — deterministic tests that the query honors ConsoleConfigurationOverride (incl. useStandardError), with null original console mode.
  • src/Build.UnitTests/TerminalLogger_Tests.cs — positive regression test driving the real QueryIsScreenAndTryEnableAnsiColorCodes path via the override: a screen-capable transmitted config auto-selects TerminalLogger; a redirected one selects ConsoleLogger. Verified it fails without the fix (returns ConsoleLogger) and passes with it.
  • src/MSBuild.UnitTests/MSBuildServer_Tests.cs — E2E guard that -tl:auto is not selected when the server build's output is redirected.

Manually verified end-to-end on WSL (Ubuntu) under a sized pseudo-terminal:

Scenario Before (shipped) After (this change)
no server, -tl:auto TerminalLogger TerminalLogger
server, -tl:auto ConsoleLogger (bug) TerminalLogger
server, -tl:on TerminalLogger TerminalLogger

Also confirmed that four alternating builds (TL-expected / not-expected) on the same reused server node each select the correct logger — no stale-state leakage.

Notes

The user-visible behavior requires a real TTY to observe, which headless CI cannot easily provide; the deterministic unit tests above exercise the exact fix via the same override seam the server node uses, without needing a terminal.

Copilot AI review requested due to automatic review settings June 16, 2026 14:26
@JanProvaznik

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

⚠️ Security scanning failed for Expert Code Review (command). Review the logs for details.

MSBuild Target Authoring Conventions — LGTM

No .targets or .props files were modified in this PR. The changes are limited to C# source files (NativeMethods.cs, OutOfProcServerNode.cs, and test files), so this dimension is not applicable.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes TerminalLogger auto-detection when MSBuild Server is enabled by ensuring ANSI/screen capability detection reflects the client terminal (transmitted TargetConsoleConfiguration) rather than the server node’s redirected stdout/stderr. This aligns -tl:auto behavior under the server with non-server behavior, particularly on Unix.

Changes:

  • Added a NativeMethods.ConsoleConfigurationOverride seam so QueryIsScreenAndTryEnableAnsiColorCodes can use client-transmitted capabilities (and avoid mutating/restoring node console mode).
  • Set/cleared the override in OutOfProcServerNode per build request so logger selection occurs using client terminal state.
  • Added unit/E2E coverage validating the override behavior and guarding against -tl:auto producing TerminalLogger ANSI output when output is redirected.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Framework/NativeMethods.cs Adds ConsoleConfigurationOverride and makes QueryIsScreenAndTryEnableAnsiColorCodes honor it (returning originalConsoleMode: null).
src/Build/BackEnd/Node/OutOfProcServerNode.cs Sets the override from the client’s transmitted console configuration and clears it after the build.
src/Framework.UnitTests/NativeMethods_Tests.cs New tests validating QueryIsScreenAndTryEnableAnsiColorCodes honors the override and returns null original console mode.
src/Build.UnitTests/TerminalLogger_Tests.cs Regression test validating -tl:auto selection honors the transmitted console capabilities via the override.
src/MSBuild.UnitTests/MSBuildServer_Tests.cs E2E regression guard that redirected output with server enabled does not contain TerminalLogger ANSI sequences.

Comment thread src/Build/BackEnd/Node/OutOfProcServerNode.cs Outdated
Comment thread src/Build/BackEnd/Node/OutOfProcServerNode.cs

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

24-Dimension Code Review — PR #14077

Fix TerminalLogger auto-detection under MSBuild Server on Unix

Dimension Result
Test Coverage & Completeness ⚠️ MODERATE — missing mixed (true,false) / (false,true) InlineData cases
Logging & Diagnostics Rigor 💬 NIT — no trace call when override is applied
Documentation Accuracy 💬 NIT — doc comment understates when the property is null

21/24 dimensions clean — no BLOCKING or MAJOR findings.


Design correctness note

Two sub-agents independently raised a concern about the ~36-line gap between setting ConsoleConfigurationOverride (line 407) and the try/finally that clears it (line 444). A validation agent read the actual code and confirmed this is not a real bug: any exception thrown in that gap propagates to HandleServerNodeBuildCommandAsync, which sets _shutdownReason = NodeEngineShutdownReason.Error; the Run() loop returns immediately on anything other than BuildCompleteReuse, so the server process terminates before any subsequent build could observe the stale override. The design is sound.


Overall assessment

The fix is architecturally correct. The ConsoleConfigurationOverride seam is the right choice — consulting ConsoleConfiguration.Provider directly from NativeMethods would create a circular assembly dependency (Microsoft.Build.FrameworkMicrosoft.Build). The layer boundary is respected. The override is set/cleared per-build with proper exception safety (server-exit semantics), the property is internal, correctly documented, and allocation-free. The E2E test and unit tests provide meaningful coverage of the bug being fixed.

The only action item worth addressing before merge is the test-coverage gap (adding the two mixed InlineData cases) to harden the regression guard against future condition-simplification errors.

Generated by Expert Code Review (command) for issue #14077 · 2.2K AIC · ⊞ 29.8K ambient context
Comment /review to run again

Comment thread src/Build.UnitTests/TerminalLogger_Tests.cs
Comment thread src/Framework/NativeMethods.cs Outdated
Comment thread src/Build/BackEnd/Node/OutOfProcServerNode.cs
Comment thread src/Build.UnitTests/TerminalLogger_Tests.cs
Comment thread src/Framework/NativeMethods.cs
@JanProvaznik

Copy link
Copy Markdown
Member Author

Thanks for the review. Addressed in 60b69a9:

  • Widened the try/finally in OutOfProcServerNode to cover all setup after the override is set, and the finally now also restores Console.Out/Console.Error. So on any failure path the original writers are restored and the override is cleared — no stale override or disposed writers on a reused server node. (Covers both inline comments on lines 408/455.)
  • Added the off-diagonal test cases (true,false) and (false,true)ConsoleLogger, pinning that both acceptAnsi and outputIsScreen are required for -tl:auto.
  • Clarified the doc comment to note ConsoleConfigurationOverride is also null while a server node is idle between builds.
  • Added a CommunicationsUtilities.Trace of the transmitted console configuration for diagnosability.

Build clean; Framework (5), TerminalLogger_Tests theory (4), and MSBuildServer_Tests (14) all green.

JanProvaznik and others added 2 commits June 17, 2026 17:43
Under MSBuild Server, TerminalLogger auto-detection runs in the server
node, whose stdout is a redirected pipe. QueryIsScreenAndTryEnableAnsiColorCodes
inspected the node's own console instead of the client's transmitted
TargetConsoleConfiguration, so -tl:auto fell back to the console logger
even from a real interactive terminal (reproduces on Unix; also mis-detected
msbuild > file.txt on Windows).

Add NativeMethods.ConsoleConfigurationOverride, set by the server node from
the client's transmitted console configuration, and consulted first by
QueryIsScreenAndTryEnableAnsiColorCodes. It is refreshed per build and
cleared in a finally, so a reused server node never observes stale state.

Fixes dotnet#13940

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- OutOfProcServerNode: widen try/finally to cover all setup after the
  override is set, and restore Console.Out/Error in the finally so a reused
  server node never observes a stale override or disposed writers on a failure
  path. Trace the transmitted console configuration for diagnosability.
- TerminalLogger_Tests: add off-diagonal (true,false)/(false,true) cases to
  pin that both acceptAnsi and outputIsScreen are required for -tl:auto.
- NativeMethods: clarify that ConsoleConfigurationOverride is also null while a
  server node is idle between builds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JanProvaznik
JanProvaznik force-pushed the tl-auto-server-unix branch from 60b69a9 to 07c10c0 Compare June 17, 2026 15:50
Comment thread src/Framework/NativeMethods.cs
@JanProvaznik
JanProvaznik enabled auto-merge (squash) June 17, 2026 17:03
@JanProvaznik
JanProvaznik merged commit ccfd927 into dotnet:main Jun 17, 2026
14 checks passed
JanProvaznik added a commit to JanProvaznik/sdk that referenced this pull request Jul 10, 2026
…ild#14077)

The SDK redistributed MSBuild 18.9.0-preview-26311-113 (source-dated 2026-06-11), which predates the TerminalLogger-under-MSBuild-Server fix (dotnet/msbuild#14077, merged 2026-06-17). With the server enabled by default, that bug caused integration tests capturing 'dotnet build' output to fail. Version.Details.props lagged behind Version.Details.xml (already at 26325-102); this aligns them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 499249b7-514f-4ecf-88bc-2466455069c5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TerminalLogger auto fails on Unix when server is enabled

3 participants