| Crates.io | cappie |
| lib.rs | cappie |
| version | 0.1.1 |
| created_at | 2025-06-21 23:19:40.487406+00 |
| updated_at | 2025-06-22 01:47:03.565038+00 |
| description | A fast JSON logger for Rust. |
| homepage | https://github.com/DitzDev/Cappie |
| repository | https://github.com/DitzDev/Cappie |
| max_upload_size | |
| id | 1721166 |
| size | 74,700 |
A fast, flexible JSON logger for Rust, inspired by Pino from Node.js.
Add to your Cargo.toml:
[dependencies]
cappie = "0.1.0"
use cappie::{Logger, Level};
fn main() {
let logger = Logger::new("my-app")
.with_level(Level::Debug);
logger.info("Application started");
logger.error("Something went wrong");
// With additional fields
logger.info_with("User logged in", |log| {
log.string("user_id", "12345")
.string("ip", "192.168.1.1")
.bool("first_time", true);
});
}
Output:
{"level":30,"time":"2024-01-15T10:30:45.123Z","name":"my-app","msg":"Application started"}
{"level":50,"time":"2024-01-15T10:30:45.124Z","name":"my-app","msg":"Something went wrong"}
{"level":30,"time":"2024-01-15T10:30:45.125Z","name":"my-app","msg":"User logged in","user_id":"12345","ip":"192.168.1.1","first_time":true}
use cappie::{Logger, PrettyFormatter};
fn main() {
let logger = Logger::new("my-app")
.with_formatter(Box::new(PrettyFormatter::new()));
logger.info("Server started");
logger.warn("Memory usage high");
logger.error("Database connection failed");
}
Output:
[10:30:45] (my-app) INFO: Server started
[10:30:45] (my-app) WARN: Memory usage high
[10:30:45] (my-app) ERROR: Database connection failed
The FlexibleFormatter gives you complete control over log output format. You can position any component anywhere, add custom colors, prefixes, suffixes, and even custom text.
use cappie::{Logger, FlexibleFormatter, ComponentType, ComponentPosition};
// Default format: [HH:mm:SS] (logger) LEVEL: message fields
let logger = Logger::new("app")
.with_formatter(Box::new(FlexibleFormatter::new()));
// Output: message LEVEL [HH:mm:SS]: fields
let logger = Logger::new("api")
.with_formatter(Box::new(
FlexibleFormatter::new()
.clear_components()
.add_message(ComponentPosition::Start, None, None, None)
.add_level(ComponentPosition::AfterMessage, Some("\x1b[31m".to_string()), Some(" ".to_string()), None)
.add_timestamp(ComponentPosition::AfterLevel, None, Some(" [".to_string()), Some("]".to_string()))
.add_custom_text(": ", ComponentPosition::AfterTime, None)
.add_fields(ComponentPosition::End, None, None, None)
));
logger.error("Database connection failed");
// Output: Database connection failed ERROR [10:30:45]:
// Output: [LEVEL] message
let logger = Logger::new("minimal")
.with_formatter(Box::new(
FlexibleFormatter::new()
.clear_components()
.add_level(ComponentPosition::Start, Some("\x1b[33m".to_string()), Some("[".to_string()), Some("]".to_string()))
.add_message(ComponentPosition::AfterLevel, None, Some(" ".to_string()), None)
));
logger.warn("This is a warning");
// Output: [WARN] This is a warning
// Output: [logger] LEVEL: message | fields (at HH:mm:SS)
let logger = Logger::new("backend")
.with_formatter(Box::new(
FlexibleFormatter::new()
.clear_components()
.add_logger_name(ComponentPosition::Start, Some("\x1b[36m".to_string()), Some("[".to_string()), Some("]".to_string()))
.add_level(ComponentPosition::AfterName, Some("\x1b[32m".to_string()), Some(" ".to_string()), None)
.add_custom_text(": ", ComponentPosition::AfterLevel, None)
.add_message(ComponentPosition::AfterLevel, None, None, None)
.add_fields(ComponentPosition::AfterMessage, None, Some(" | ".to_string()), None)
.add_timestamp(ComponentPosition::End, Some("\x1b[90m".to_string()), Some(" (at ".to_string()), Some(")".to_string()))
));
logger.info_with("Server started", |log| { log.number("port", 8080); });
// Output: [backend] INFO: Server started | port=8080 (at 10:30:45)
// Output: 🚀 [HH:mm:SS] {logger} <LEVEL> → message 📊 fields
let logger = Logger::new("colorful")
.with_formatter(Box::new(
FlexibleFormatter::new()
.clear_components()
.add_custom_text("🚀 ", ComponentPosition::Start, Some("\x1b[95m".to_string()))
.add_timestamp(ComponentPosition::Start, Some("\x1b[94m".to_string()), Some("[".to_string()), Some("]".to_string()))
.add_logger_name(ComponentPosition::AfterTime, Some("\x1b[96m".to_string()), Some(" {".to_string()), Some("}".to_string()))
.add_level(ComponentPosition::AfterName, Some("\x1b[93m".to_string()), Some(" <".to_string()), Some(">".to_string()))
.add_custom_text(" → ", ComponentPosition::AfterLevel, Some("\x1b[97m".to_string()))
.add_message(ComponentPosition::AfterLevel, Some("\x1b[92m".to_string()), None, None)
.add_fields(ComponentPosition::End, Some("\x1b[91m".to_string()), Some(" 📊 ".to_string()), None)
));
logger.info_with("App started", |log| { log.string("version", "1.0.0"); });
// Output: 🚀 [10:30:45] {colorful} <INFO> → App started 📊 version=1.0.0
The FlexibleFormatter supports these component types:
ComponentType::Timestamp - The log timestampComponentType::LoggerName - The logger nameComponentType::Level - The log level (INFO, ERROR, etc.)ComponentType::Message - The log messageComponentType::Fields - Additional structured fieldsComponentType::CustomText(String) - Custom static textYou can position components at these locations:
ComponentPosition::Start - At the very beginningComponentPosition::AfterTime - After the timestampComponentPosition::AfterName - After the logger nameComponentPosition::AfterLevel - After the log levelComponentPosition::AfterMessage - After the messageComponentPosition::End - At the very endFlexibleFormatter::new()
// Clear all default components
.clear_components()
// Add components with full control
.add_component(ComponentType::Timestamp, ComponentPosition::Start, color, prefix, suffix)
// Convenience methods for common components
.add_timestamp(position, color, prefix, suffix)
.add_logger_name(position, color, prefix, suffix)
.add_level(position, color, prefix, suffix)
.add_message(position, color, prefix, suffix)
.add_fields(position, color, prefix, suffix)
.add_custom_text("text", position, color)
// Configuration
.with_time_format("%H:%M:%S")
.with_no_colors()
use cappie::{Logger, PrettyFormatter, Level};
fn main() {
let logger = Logger::new("my-app")
.with_formatter(Box::new(
PrettyFormatter::new()
.with_color(Level::Error, "\x1b[91m") // Bright red
.with_color(Level::Warn, "\x1b[93m") // Bright yellow
.with_time_format("%Y-%m-%d %H:%M:%S")
));
logger.warn("Custom colored warning");
logger.error("Custom colored error");
}
| Level | Value | Description |
|---|---|---|
TRACE |
10 | Very detailed information |
DEBUG |
20 | Debug information |
INFO |
30 | General information |
WARN |
40 | Warning messages |
ERROR |
50 | Error messages |
FATAL |
60 | Fatal errors |
Create contextual loggers that inherit parent configuration:
let parent = Logger::new("app");
let auth_logger = parent.child("auth");
let db_logger = parent.child("database");
auth_logger.info("User authenticated"); // Outputs: app.auth
db_logger.error("Connection timeout"); // Outputs: app.database
Log to console and file simultaneously:
use cappie::{Logger, FileOutput, MultiOutput, StdoutOutput};
let logger = Logger::new("my-app")
.with_output(Box::new(
MultiOutput::new()
.add_output(Box::new(StdoutOutput))
.add_output(Box::new(FileOutput::new("app.log")))
));
logger.info("This goes to both console and file");
Add fields that appear in every log entry:
let logger = Logger::new("my-app")
.with_field("version", "1.0.0")
.with_field("env", "production")
.with_field("service", "api-server");
logger.info("App started"); // Includes version, env, and service fields
Add contextual information to specific log entries:
logger.error_with("Database query failed", |log| {
log.string("query", "SELECT * FROM users")
.number("duration_ms", 1500)
.string("table", "users")
.bool("timeout", true);
});
Cappie supports full ANSI color customization:
use cappie::{Logger, FlexibleFormatter, ComponentPosition, ComponentType};
let logger = Logger::new("colorful-app")
.with_formatter(Box::new(
FlexibleFormatter::new()
.clear_components()
.add_timestamp(ComponentPosition::Start, Some("\x1b[32m".to_string()), Some("[".to_string()), Some("]".to_string())) // Green
.add_level(ComponentPosition::AfterTime, Some("\x1b[33m".to_string()), Some(" ".to_string()), None) // Yellow
.add_message(ComponentPosition::AfterLevel, Some("\x1b[31m".to_string()), Some(": ".to_string()), None) // Red
));
| Color | Code | Color | Code |
|---|---|---|---|
| Black | \x1b[30m |
Bright Black | \x1b[90m |
| Red | \x1b[31m |
Bright Red | \x1b[91m |
| Green | \x1b[32m |
Bright Green | \x1b[92m |
| Yellow | \x1b[33m |
Bright Yellow | \x1b[93m |
| Blue | \x1b[34m |
Bright Blue | \x1b[94m |
| Magenta | \x1b[35m |
Bright Magenta | \x1b[95m |
| Cyan | \x1b[36m |
Bright Cyan | \x1b[96m |
| White | \x1b[37m |
Bright White | \x1b[97m |
Run the included examples:
# Basic JSON and pretty logging
cargo run --example basic
# Pretty logging with colors and fields
cargo run --example pretty
# Custom colors, outputs, and configurations
cargo run --example custom
# Flexible formatter examples with various layouts
cargo run --example flexible
// Create a new logger
Logger::new("app-name")
// Configuration
.with_level(Level::Debug)
.with_formatter(Box::new(FlexibleFormatter::new()))
.with_output(Box::new(StdoutOutput))
.with_field("key", "value")
// Logging methods
.trace("message")
.debug("message")
.info("message")
.warn("message")
.error("message")
.fatal("message")
// Logging with fields
.info_with("message", |log| {
log.string("key", "value")
.number("count", 42)
.bool("success", true);
})
// Create child logger
.child("module-name")
FlexibleFormatter::new()
.with_time_format("%H:%M:%S")
.clear_components()
// Add specific components
.add_timestamp(position, color, prefix, suffix)
.add_logger_name(position, color, prefix, suffix)
.add_level(position, color, prefix, suffix)
.add_message(position, color, prefix, suffix)
.add_fields(position, color, prefix, suffix)
.add_custom_text("text", position, color)
// Generic component addition
.add_component(component_type, position, color, prefix, suffix)
.with_no_colors()
PrettyFormatter::new()
.with_time_format("%H:%M:%S")
.with_color(Level::Error, "\x1b[91m")
.with_no_colors()
| Feature | JsonFormatter | PrettyFormatter | FlexibleFormatter |
|---|---|---|---|
| JSON Output | ✅ | ❌ | ❌ |
| Human Readable | ❌ | ✅ | ✅ |
| Custom Colors | ❌ | ✅ | ✅ |
| Custom Positioning | ❌ | ❌ | ✅ |
| Custom Text | ❌ | ❌ | ✅ |
| Prefixes/Suffixes | ❌ | ❌ | ✅ |
| Performance | Fastest | Fast | Fast |
| Use Case | Machine parsing | Development | Custom layouts |
Cappie is designed for high performance:
// API request logging with flexible format
let api_logger = Logger::new("api")
.with_formatter(Box::new(
FlexibleFormatter::new()
.clear_components()
.add_custom_text("🌐 ", ComponentPosition::Start, Some("\x1b[94m".to_string()))
.add_timestamp(ComponentPosition::Start, Some("\x1b[90m".to_string()), None, None)
.add_level(ComponentPosition::AfterTime, Some("\x1b[32m".to_string()), Some(" [".to_string()), Some("]".to_string()))
.add_message(ComponentPosition::AfterLevel, None, Some(" ".to_string()), None)
.add_fields(ComponentPosition::End, Some("\x1b[36m".to_string()), Some(" → ".to_string()), None)
));
api_logger.info_with("Request processed", |log| {
log.string("method", "GET")
.string("path", "/api/users")
.number("status", 200)
.number("duration_ms", 45);
});
// Database logging with custom format
let db_logger = Logger::new("database")
.with_formatter(Box::new(
FlexibleFormatter::new()
.clear_components()
.add_custom_text("💾 DB ", ComponentPosition::Start, Some("\x1b[95m".to_string()))
.add_level(ComponentPosition::Start, Some("\x1b[91m".to_string()), Some("[".to_string()), Some("]".to_string()))
.add_message(ComponentPosition::AfterLevel, None, Some(" ".to_string()), None)
.add_timestamp(ComponentPosition::End, Some("\x1b[90m".to_string()), Some(" @".to_string()), None)
.add_fields(ComponentPosition::AfterMessage, Some("\x1b[33m".to_string()), Some(" {".to_string()), Some("}".to_string()))
));
| Feature | Cappie | Pino |
|---|---|---|
| JSON Logging | ✅ | ✅ |
| Pretty Printing | ✅ | ✅ |
| Flexible Formatting | ✅ | ❌ |
| Child Loggers | ✅ | ✅ |
| Custom Formatters | ✅ | ✅ |
| Multiple Outputs | ✅ | Limited |
| Custom Colors | ✅ | Limited |
| Custom Positioning | ✅ | ❌ |
| Performance | Very Fast | Fast |
| Language | Rust | JavaScript |
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.