Standard Input and Output
stderr()
std::io::stderr() constructs and returns a zero-sized std::io::Stderr handle to the current process's standard error stream (file descriptor 2). Like Stdout, Stderr implements std::io::Write and std::io::IsTerminal, and provides .lock() to obtain an exclusive StderrLock<'static> guard.
Methods and Characteristics of std::io::Stderr
| Property / Method | Detail |
|---|---|
| Constructor | pub const fn stderr() -> Stderr (0 bytes on the stack) |
| Buffering | Unbuffered — every write call on Stderr or StderrLock invokes the OS write syscall immediately without buffering in user space |
| Thread synchronization | Global re-entrant lock; .lock() returns StderrLock<'static> |
| Formatting macros | eprint!(...) and eprintln!(...) lock stderr() and format directly to it |
| Terminal detection | io::stderr().is_terminal() checks if stderr is attached to a TTY (e.g., to enable ANSI color codes on error logs) |
Preventing Interleaved Multi-Line Error Reports with stderr().lock()
Because Stderr is unbuffered, calling eprintln! multiple times or using multiple write! calls inside a single diagnostic printer can interleave with eprintln! calls from other threads. Acquiring let mut err = io::stderr().lock(); (and optionally wrapping it in a BufWriter for a multi-line stack trace) ensures the entire multi-line error block is emitted as one contiguous unit without thread interleaving:
use std::io::{self, IsTerminal, Write};
fn emit_structured_error(code: &str, message: &str, hint: &str) -> io::Result<()> {
let mut err = io::stderr().lock();
let use_color = err.is_terminal();
if use_color {
writeln!(err, "\x1b[1;31merror[{code}]\x1b[0m: {message}")?;
} else {
writeln!(err, "error[{code}]: {message}")?;
}
writeln!(err, " = help: {hint}")?;
Ok(())
}
fn main() -> io::Result<()> {
emit_structured_error(
"CFG01",
"missing required `DATABASE_URL` environment variable",
"set `DATABASE_URL=postgres://localhost/app` before starting",
)?;
println!("main completed");
Ok(())
}
error[CFG01]: missing required `DATABASE_URL` environment variable
= help: set `DATABASE_URL=postgres://localhost/app` before starting
main completed