Feature request description
datadog-ci writes several of its own diagnostics — and the datadog-ci v<version> banner — to stdout. This corrupts captured output: datadog-ci trace -- <cmd> runs the wrapped command with stdio: ['inherit', 'inherit', 'pipe'], so the child's stdout is fd 1 and its bytes are captured verbatim by VAR=$(datadog-ci trace -- cmd). Any diagnostic the CLI also writes to fd 1 gets mixed into that capture. When the wrapped command emits a secret (e.g. TOKEN=$(... vault write -field=token ...)), the captured value gains an extra line of diagnostic text and is rejected downstream ("configured Vault token contains non-printable characters"). The corruption is intermittent and load-correlated (e.g. the --no-fail note only fires when the span report fails under intake throttling).
The diagnostics currently written to stdout that shouldn't be:
- the
--no-fail note (trace.ts)
- the unsupported-CI-provider message (shared
CustomSpanCommand, helper.ts)
- the missing-API-key message (shared
CustomSpanCommand, helper.ts)
- the
datadog-ci v<version> banner (printed on every invocation)
Separately, the banner is spammy: in CI where the CLI runs many times (e.g. many trace -- wrap per step), it repeats on every call with no per-run value, and there's no way to turn it off.
Solution
- Route all of these diagnostics, and the banner, to stderr. This keeps them out of captured stdout, consistent with the adjacent error paths that already use
context.stderr. The banner mirrors the resolved command's --log-format, so it stays a JSON line in JSON mode.
- Add
DD_CI_SKIP_VERSION_BANNER (1/true) to suppress the banner entirely. It follows the existing DD_CI_-prefixed toggle convention (e.g. DD_CI_BYPASS_SITE_VALIDATION) and the 1/true truthiness used by DD_BETA_COMMANDS_ENABLED.
Additional context
Command
trace
Feature request description
datadog-ciwrites several of its own diagnostics — and thedatadog-ci v<version>banner — to stdout. This corrupts captured output:datadog-ci trace -- <cmd>runs the wrapped command withstdio: ['inherit', 'inherit', 'pipe'], so the child's stdout is fd 1 and its bytes are captured verbatim byVAR=$(datadog-ci trace -- cmd). Any diagnostic the CLI also writes to fd 1 gets mixed into that capture. When the wrapped command emits a secret (e.g.TOKEN=$(... vault write -field=token ...)), the captured value gains an extra line of diagnostic text and is rejected downstream ("configured Vault token contains non-printable characters"). The corruption is intermittent and load-correlated (e.g. the--no-failnote only fires when the span report fails under intake throttling).The diagnostics currently written to stdout that shouldn't be:
--no-failnote (trace.ts)CustomSpanCommand,helper.ts)CustomSpanCommand,helper.ts)datadog-ci v<version>banner (printed on every invocation)Separately, the banner is spammy: in CI where the CLI runs many times (e.g. many
trace --wrap per step), it repeats on every call with no per-run value, and there's no way to turn it off.Solution
context.stderr. The banner mirrors the resolved command's--log-format, so it stays a JSON line in JSON mode.DD_CI_SKIP_VERSION_BANNER(1/true) to suppress the banner entirely. It follows the existingDD_CI_-prefixed toggle convention (e.g.DD_CI_BYPASS_SITE_VALIDATION) and the1/truetruthiness used byDD_BETA_COMMANDS_ENABLED.Additional context
Command
trace