Debugging and logging are two of the most crucial skills every Rustacean (a.k.a. Rust developer) needs to master! Whether you're tracking down a mysterious bug or leaving yourself notes in the form of logs, Rust has powerful tools to make the process smooth and efficient.
Debugging with println!
- The Classic Approach
The simplest and most commonly used way to debug in Rust is by using println!
. It's like writing sticky notes all over your code to track what's happening.
fn main() {
let number = 42;
println!("The answer is: {}", number);
}
Why use println!
?
- It's simple and works anywhere.
- No extra setup needed.
- Good for quick debugging.
Downside? You might accidentally leave println!
all over your production code! Oops.
The Debug Trait {:?}
Rust provides a built-in way to print complex structures using Debug
. Just slap {:?}
in your println!
and add #[derive(Debug)]
to your struct.
#[derive(Debug)]
struct User {
name: String,
age: u8,
}
fn main() {
let user = User {
name: String::from("Alice"),
age: 30,
};
println!("User info: {:?}", user);
}
Pro Tip: Use {:#?}
for a pretty-printed version!
Using the log
Crate for Proper Logging
If you need real logging (not just println!
spam), Rust has the log
crate, which provides different log levels:
trace!
- Super detailed (for deep debugging).debug!
- Useful debug info.info!
- General app information.warn!
- Something seems fishy!error!
- Major problem!
Setting up log
with env_logger
First, add this to Cargo.toml
:
[dependencies]
log = "0.4"
env_logger = "0.10"
Then, initialize the logger:
use log::{info, warn, error};
use env_logger;
fn main() {
env_logger::init();
info!("Application has started!");
warn!("This is a warning! Proceed with caution.");
error!("Oh no! Something went wrong.");
}
Pro Tip: Run your program with RUST_LOG=info cargo run
to see logs in action!
Debugging with dbg!()
- The One-Liner Savior
The dbg!()
macro is like println!
, but even better!
fn main() {
let x = 10;
dbg!(x * 2);
}
Why use dbg!()
?
- Prints both the expression and its value.
- Outputs to stderr, keeping stdout clean.
- Automatically returns the value, so you can use it inline!
Using backtrace
for Advanced Debugging
Sometimes, errors don't tell you where they happened. That's where backtraces come in handy!
First, enable backtracing:
RUST_BACKTRACE=1 cargo run
Then, use .unwrap()
on an error-prone operation:
fn main() {
let numbers = vec![1, 2, 3];
println!("This will crash: {}", numbers[10]); // Out of bounds!
}
Pro Tip: If Rust crashes, RUST_BACKTRACE=full
gives you even more juicy details!
Conclusion
println!
- Good for quick checks. dbg!()
- Great for debugging expressions. log
crate - Professional logging with log levels. backtrace
- Track down those sneaky crashes.
0 Comments