Rust
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Ownership and Borrowing
-
Section 4: Structuring Data
-
Section 5: Collections and Error Handling
-
Section 6: Traits and Generics
-
Section 7: Concurrency
-
Section 8: Building for the Web
-
Section 9: Memory and Performance
-
Section 10: More Standard Library and Ecosystem
-
Section 11: Advanced Rust
-
Section 12: Rust for Systems and WebAssembly
-
Section 13: Tooling and Best Practices
-
Section 14: Data Structures and Algorithms in Rust
-
Section 15: Practical Projects
-
Section 16: Interview Practice
-
Section 17: std::collections In Depth
-
Section 18: std::io and std::fs In Depth
-
Section 19: std::net
-
Section 20: std::option and std::result In Depth
-
Section 21: std::iter In Depth
-
Section 22: std::sync In Depth
-
Section 23: std::string and std::str
-
Section 24: Cargo and Crates.io Ecosystem
-
Section 25: Popular Crates Ecosystem
-
Section 26: Rust Memory Model Deep Dive
-
Section 27: More Practice Exercises
-
Section 28: More Interview Practice
-
Section 29: Async Rust Deep Dive
-
Section 30: Tokio Ecosystem In Depth
-
Section 31: Error Handling Ecosystem Deep Dive
-
Section 32: Serde In Depth
-
Section 33: Web Development with Rust Deep Dive
-
Section 34: Database Access Ecosystem
-
Section 35: Rust for Embedded Systems Deep Dive
-
Section 36: Rust Macros In Depth
-
Section 37: Advanced Trait System
-
Section 38: Unsafe Rust In Depth
-
Section 39: Rust CLI Development
-
Section 40: Testing Ecosystem Deep Dive
-
Section 41: WebAssembly Deep Dive
-
Section 42: Rust Design Patterns
-
Section 43: More Data Structures in Rust
-
Section 44: Final Practice Projects
-
Section 45: Rust Performance Optimization
-
Section 46: Rust Ecosystem Tooling
-
Section 47: More Interview and Review
204: Colored Terminal Output
I've always found that plain white text in a terminal is a nightmare for debugging. When you're scanning through hundreds of lines of logs, your eyes just glaze over. That's why I always integrate color into my CLI tools as early as possible. It transforms a wall of text into something scannable, where a red "ERROR" actually jumps out at you.
In Rust, you could manually print ANSI escape codes—those weird strings like \x1b[31m—but that's a recipe for a headache. Instead, I use the colored crate. It's lightweight and provides a very intuitive extension trait that lets you call methods like .red() or .bold() directly on strings.
Adding the dependency
First, let's get the crate into our project. I'm going to build a small "System Health Monitor" that reports the status of different services. Run this in your terminal:
cargo add colored
Setting up our Health Monitor
I want to represent different service states using an enum. This keeps our logic clean. I'll start by importing Colorize, which is the trait that actually adds the coloring methods to our strings.
use colored::*;
enum ServiceStatus {
Online,
Degraded,
Offline,
}
fn main() {
let services = vec![
("Database", ServiceStatus::Online),
("Cache", ServiceStatus::Degraded),
("Auth-API", ServiceStatus::Offline),
];
for (name, status) in services {
print_status(name, status);
}
}
The "Type Mismatch" stumble
Now, here is where I usually trip up when I'm rushing. I want to print the status in a color that matches its meaning. I'll try to call .green() or .red() directly on the enum variant. Let's see what happens:
fn print_status(name: &str, status: ServiceStatus) {
// I'll try to color the status directly here
match status {
ServiceStatus::Online => println!("{}: {}", name, status.green()),
ServiceStatus::Degraded => println!("{}: {}", name, status.yellow()),
ServiceStatus::Offline => println!("{}: {}", name, status.red()),
}
}
If you try to compile this, the compiler is going to scream at you. Why? Because ServiceStatus is an enum, not a string. The colored crate extends String and &str, but it has no idea what to do with my custom ServiceStatus type. I forgot that I need to turn the status into a string first.
Fixing the logic and polishing
To fix this, I'll derive Debug on my enum so I can easily turn it into a string using the format! macro. This is the fastest way to get the variant name as a string without writing a manual Display implementation.
#[derive(Debug)]
enum ServiceStatus {
Online,
Degraded,
Offline,
}
fn print_status(name: &str, status: ServiceStatus) {
// We format the enum into a string first, THEN call the color method
match status {
ServiceStatus::Online => {
println!("{}: {}", name, format!("{:?}", status).green().bold());
}
ServiceStatus::Degraded => {
println!("{}: {}", name, format!("{:?}", status).yellow());
}
ServiceStatus::Offline => {
println!("{}: {}", name, format!("{:?}", status).red().underline());
}
}
}
I added .bold() and .underline() just to show how you can chain these modifiers. Now, when you run this, the "Online" status is a bold green, "Degraded" is yellow, and "Offline" is a red underlined warning. It's a small change, but the difference in readability is massive.
📋 Practical Task
Build a Color-Coded Log Parser
Create a program that simulates reading a log file. Define a list of strings where some lines start with [INFO], some with [WARN], and some with [ERROR].
- Use the
coloredcrate to print the lines to the terminal. [INFO]lines should be blue.[WARN]lines should be yellow.[ERROR]lines should be red and bold.- Any line that doesn't match those prefixes should be printed in the default terminal color.
Hint: Use .starts_with() to check the beginning of each log line before applying the color.
There are no comments for now.