Skip to content

Fix preparer output routing to preserve stdout/stderr distinction#144356

Merged
mark-vieira merged 3 commits intoelastic:mainfrom
mark-vieira:fix/preparer-output-routing
Mar 17, 2026
Merged

Fix preparer output routing to preserve stdout/stderr distinction#144356
mark-vieira merged 3 commits intoelastic:mainfrom
mark-vieira:fix/preparer-output-routing

Conversation

@mark-vieira
Copy link
Copy Markdown
Contributor

@mark-vieira mark-vieira commented Mar 16, 2026

Summary

The recent ServerLauncher changes (#143712) route all preparer (server-cli) text output to stderr, breaking downstream tools that expect output like --version and --help on stdout.

This PR fixes the issue by multiplexing stdout and stderr onto a single pipe using byte-level mode switching, then demultiplexing in the launcher:

  • Installs an OutputStreamMux in the preparer that replaces both System.out and System.err with mux channels writing to a single pipe. Mode byte 0x01 marks stdout, 0x02 marks stderr. Mode markers are only emitted on transitions, making same-channel writes zero-overhead.
  • The launcher pipes the preparer's stderr through a PreparerOutputPump that reads raw bytes, tracks the current mode, and routes data to the correct stream.
  • Untagged output defaults to stdout, matching pre-ServerLauncher behavior.

This byte-level approach (as opposed to the earlier line-based tagging) correctly preserves stdout/stderr distinction even for partial-line output like print() without a trailing newline (e.g. password prompts).

Test plan

  • Unit tests for OutputStreamMux (mode emission, lazy switching, interleaved partial lines, UTF-8)
  • Unit tests for PreparerOutputPump (mode switching, default mode, marker stripping)
  • Updated CliToolLauncherTests verifying mode markers on stdout/stderr output
  • Reverted packaging test assertions back to checking stdout
  • Reverted PackagingTestCase.assertElasticsearchFailure workaround (no longer needed)

@mark-vieira mark-vieira requested a review from a team as a code owner March 16, 2026 20:28
@mark-vieira mark-vieira added >refactoring :Core/Infra/CLI CLI utilities, scripts, and infrastructure labels Mar 16, 2026
@elasticsearchmachine elasticsearchmachine added Team:Core/Infra Meta label for core/infra team v9.4.0 labels Mar 16, 2026
@elasticsearchmachine
Copy link
Copy Markdown
Collaborator

Pinging @elastic/es-core-infra (Team:Core/Infra)

The ServerLauncher routes all preparer text output to stderr,
breaking tools that expect --version/--help on stdout. Tag
stderr-destined lines at the stream level so the launcher can
dispatch them correctly. Untagged output defaults to stdout.

Made-with: Cursor
@mark-vieira mark-vieira force-pushed the fix/preparer-output-routing branch from 83e5b66 to ce74308 Compare March 16, 2026 21:38
Replace line-based stderr tagging with a byte-level mode-switching
protocol so that stdout/stderr routing is preserved even for
partial-line output (e.g. print() without a trailing newline).

Made-with: Cursor
stdout.flush();
stderr.flush();
} catch (IOException e) {
// stream closed, nothing to do
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we avoid swallowing ioexceptions? here and below

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. We now rethrow UncheckedIOException.

*
* <p> The preparer uses an {@code OutputStreamMux} (in the cli-launcher module) to
* multiplex its stdout and stderr onto a single pipe. Mode byte {@link #STDOUT_MODE}
* ({@code 0x01}) switches to stdout; {@link #STDERR_MODE} ({@code 0x02}) switches to
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

so this assumes that 0x01 and 0x02 never appear in the actual streams, right? can we guarantee that? (I think we can, unicode shouldn't have any dangling high bit 0 bytes and these are unprintable codes, but just want to be sure).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah. Assuming we aren't writing any non-unicode to the terminal here (which we shouldn't be).

@mark-vieira mark-vieira merged commit 0ddc2ba into elastic:main Mar 17, 2026
35 of 36 checks passed
michalborek pushed a commit to michalborek/elasticsearch that referenced this pull request Mar 23, 2026
…astic#144356)

* Fix preparer output routing to preserve stdout/stderr

The ServerLauncher routes all preparer text output to stderr,
breaking tools that expect --version/--help on stdout. Tag
stderr-destined lines at the stream level so the launcher can
dispatch them correctly. Untagged output defaults to stdout.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Core/Infra/CLI CLI utilities, scripts, and infrastructure >refactoring Team:Core/Infra Meta label for core/infra team v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants