Make stderr output exclusive to fatal paths and consistent across all fatal paths

Abierto
#8,623 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

@achamayou ya está trabajando en esto.

Desde el 5/11/2026.

  • #8690 de @achamayou — abierto

Evaluación

Dificultad
5/5
Tiempo estimado
Más de una semana
Aptitud para principiantes
35/100
Tipo de issue
Nueva funcionalidad
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
cpp, rust

Línea de trabajo

Start by reading the console logger and fatal reporting code in include/ccf/ds/logger.h and src/host/runtime_control.h, then trace the join callers in src/node/node_state.h and the post-join failure examples in src/node/rpc/frontend.h and src/host/socket.h. Review the Rust panic-hook handling in src/rust/ccf-app/src/lib.rs and existing regression tests for process output. Done means documenting the stderr contract and scope, covering fatal and recoverable paths, and ensuring fatal diagnostics avoid confidential request or KV data.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Is your feature request related to a problem? Please describe.
CCF's stderr is not currently a consistent indicator of fatal failure.
Some fatal paths write to stderr, while others log only to stdout before aborting or exiting.
Operators therefore cannot rely on an empty stderr to mean that no fatal error occurred, or use stderr alone to capture fatal diagnostics.

Source inspection found the following behavior:

  • Normal framework and application logging uses stdout at every severity, including fail and fatal, for both text and JSON console loggers. LOG_FATAL_FMT and CCF_APP_FATAL do not themselves terminate execution or write to stderr.
  • RuntimeControlImpl::report_fatal_error() writes and flushes the first reported error to stderr, then requests enclave shutdown. All four current production call sites are on the join path: oversized join responses; non-retryable transport/TLS failures, including certificate trust failures; fatal join client errors, except the supported fresh-snapshot retry case; and startup-snapshot installation failures during join completion.
  • CLI11 writes command-line parsing errors to stderr. Help and version output use stdout.
  • files::slurp() writes required-file open/read failures to stderr and exits when optional == false.
  • Post-join fatal paths can log to stdout and call abort() without a CCF stderr diagnostic. Examples include transaction serialisation failure in the RPC frontend and socket resolve/listen failure handlers. abort() itself does not print a diagnostic; a supervising shell may separately report the signal.
  • Native assertion failures can emit stderr diagnostics when assertions are enabled. Uncaught C++ exceptions and Rust's default panic hook can also produce runtime diagnostics. The experimental Rust SDK suppresses panic diagnostics for caught application-callback panics, but forwards other panics to the previously installed hook.
  • Applications and dependencies can write directly to stderr, for example through Rust's eprint!/eprintln!. Such output is not governed by CCF's logger today.

Describe the solution you'd like
Establish and enforce the following contract for CCF node stderr:

  1. Only fatal paths write to stderr. Recoverable errors, warnings, and ordinary application logging must not produce stderr output.
  2. All fatal paths consistently write a useful diagnostic to stderr before the node terminates, including failures after joining the network. This must not depend on whether the path uses report_fatal_error(), logs and aborts, or exits through another mechanism.

Preserve useful stdout logging while ensuring stderr has the same meaning across startup, join, and steady-state operation.
Document the contract and its scope, including application/dependency writes and runtime-generated diagnostics.
Distinguish actual fatal termination paths from the fatal log-level label: emitting a log entry at that level does not currently imply termination.
Fatal diagnostics must not expose confidential request or KV data.
Add regression coverage demonstrating both sides of the contract: fatal paths emit stderr diagnostics, and recoverable paths do not.

Describe alternatives you've considered
Continue parsing stdout severity labels and combining them with process exit status.
This leaves stderr inconsistent, and the fatal severity label alone is not equivalent to a fatal termination path.
Routing all fail or fatal log entries to stderr without considering control flow would not establish the requested fatal-path-only contract.

Additional context
Findings are based on source inspection at commit 4bb1570da7264b0daa417f2c6e4e497124f0b8d0, rather than an exhaustive runtime reproduction.
Relevant source locations:

Lenguaje dominante
C++
Estrellas
876
Forks
264
Merge medio
1 d 16 h
PR fusionados (30 d)
127

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de microsoft/CCF

Todos los issues de microsoft/CCF

Issues similares

Más issues de C++

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.