63

One uses this to send output to stdout:

println!("some output")

I think there is no corresponding macro to do the same for stderr.

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
tshepang
  • 12,111
  • 21
  • 91
  • 136

5 Answers5

110

After Rust 1.19

As of Rust 1.19, you can use the eprint and eprintln macros:

fn main() {
    eprintln!("This is going to standard error!, {}", "awesome");
}

This was originally proposed in RFC 1896.

Before Rust 1.19

You can see the implementation of println! to dive into exactly how it works, but it was a bit overwhelming when I first read it.

You can format stuff to stderr using similar macros though:

use std::io::Write;

let name = "world";
writeln!(&mut std::io::stderr(), "Hello {}!", name);

This will give you a unused result which must be used warning though, as printing to IO can fail (this is not something we usually think about when printing!). We can see that the existing methods simply panic in this case, so we can update our code to do the same:

use std::io::Write;

let name = "world";
let r = writeln!(&mut std::io::stderr(), "Hello {}!", name);
r.expect("failed printing to stderr");

This is a bit much, so let's wrap it back in a macro:

use std::io::Write;

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let name = "world";
    println_stderr!("Hello {}!", name)
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • So, it's `println_stderr!("Hello {}!", name)` vs. `writeln!(&mut std::stdio::stderr(), "Hello {}!", name)`, both which do pretty much the same thing? – tshepang Dec 24 '14 at 05:49
  • 1
    They do the same thing, but the macro handles the fail case (the return value) without all the cruft. Without it, you get a warning. – Josh Jun 01 '16 at 00:56
  • 2
    You could also do `writeln!(...).unwrap();` to handle possible failure in the simplest way. – Pavel Strakhov Aug 25 '16 at 12:43
20

print! and println! are convenience methods for writing to standard output. There are other macros with the same formatting features available for different tasks:

To write to the standard error stream, you can use e.g. writeln! like this:

use std::io::Write;

fn main() {
    let mut stderr = std::io::stderr();
    writeln!(&mut stderr, "Error!").unwrap();
}
tshepang
  • 12,111
  • 21
  • 91
  • 136
Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
3

It's done so:

use std::io::Write;

fn main() {
    std::io::stderr().write(b"some output\n");
}

You can test it by sending the program output to /dev/null to ensure it works (I ignore the warning):

$ rustc foo.rs && ./foo > /dev/null
foo.rs:4:5: 4:42 warning: unused result which must be used, #[warn(unused_must_use)] on by default
foo.rs:4     io::stderr().write(b"some output\n");
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
some output

Similarly, one can do the following for stdout:

use std::io::Write;

fn main() {
    std::io::stdout().write(b"some output\n");
}

I think this means println! is just a convenience: it's shorter and it also allows some formatting. As an example of the latter, the following displays 0x400:

println!("0x{:x}", 1024u)
tshepang
  • 12,111
  • 21
  • 91
  • 136
3

While not answering the precise question, maybe it’s of interest that there’s a log crate which specifies an interface for leveled logging that other crates (e.g. env_logger) can fulfill.

The output of such logging will be sent to stderr, and there are additional benefits for users, such as specifying the log level.

This is how using such a logger could look like:

#[macro_use]
extern crate log;
extern crate env_logger;

fn main() {
    env_logger::init().unwrap();
    error!("this is printed by default");
}

(Example adapted from http://burntsushi.net/rustdoc/env_logger/index.html#example)

Michael
  • 776
  • 1
  • 11
  • 20
0

Goal

stderr!("Code {}: Danger, Will Robinson!  Danger!", 42);

Notes

The other answers generate an unused import warning with the latest nightly, so here's a modern macro that Just Works TM.

Code

macro_rules! stderr {
    ($($arg:tt)*) => (
        use std::io::Write;
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr (file handle closed?): {}", x),
        }
    )
}
  • 1
    My answer has no warnings on the nightly on the [Rust Playground nightly](http://is.gd/XEFTKk). What are you seeing? – Shepmaster Sep 22 '15 at 01:41
  • This solution doesn't work: error: imports are not allowed after non-item statements – Maxime Chéramy Jan 31 '16 at 10:54
  • This happens for me if you use the macro in a block after another statement. If you wrap the inner bit with the `use` and `match` in another block, it works for me. So `($($arg:tt)*) => ({ use ... })` – zstewart Feb 07 '16 at 02:56