6 releases (2 stable)
| 1.1.2 | Aug 15, 2025 |
|---|---|
| 1.0.0 | Aug 14, 2025 |
| 0.2.1 | Oct 18, 2024 |
| 0.1.1 | Oct 1, 2024 |
#196 in Debugging
235 downloads per month
140KB
2.5K
SLoC
firo_logger
A high-performance, feature-rich logger for Rust applications with colored output, structured logging, file rotation, async logging, and advanced configuration.
Features
- ✨ Colored console output with customizable colors
- 📊 Structured logging with JSON format support
- 📁 File logging with automatic rotation (size-based and time-based)
- ⚡ Async logging for high-performance applications
- 🎯 Level filtering with module-specific filters
- 🔒 Thread-safe with minimal overhead
- 📍 Caller information (file, line, module)
- 🏷️ Custom metadata support
- 🌍 Environment configuration support
- 🏗️ Builder pattern for easy configuration
- 🔄 Log rotation with configurable retention
- 🚀 Performance optimized with buffering and batching
- 📈 Statistics and monitoring built-in
- 🔧 Backwards compatibility with legacy API
Quick Start
Add this to your Cargo.toml:
[dependencies]
firo_logger = "0.3.0"
Basic Usage
use firo_logger::{init_default, log_info, log_error, log_success};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize the logger with default settings
init_default()?;
// Log some messages
log_info!("Application started");
log_success!("Configuration loaded successfully");
log_error!("Failed to connect to database: {}", "Connection timeout");
Ok(())
}
Advanced Configuration
use firo_logger::{LoggerConfig, LogLevel, OutputFormat, init};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = LoggerConfig::builder()
.level(LogLevel::Debug)
.format(OutputFormat::Json)
.console(true)
.colors(true)
.file("app.log")
.rotate_by_size(10 * 1024 * 1024, 5) // 10MB, keep 5 files
.async_logging(1000)
.include_caller(true)
.include_thread(true)
.metadata("app", "my-app")
.metadata("version", "1.0.0")
.build();
init(config)?;
log_info!("Logger initialized with custom configuration");
Ok(())
}
Configuration Options
Environment Variables
The logger can be configured using environment variables:
FIRO_LOG_LEVEL: Set log level (ERROR,WARNING,INFO,SUCCESS,DEBUG)FIRO_LOG_FILE: Set log file pathFIRO_LOG_FORMAT: Set output format (text,json,plain)NO_COLOR: Disable colored outputFORCE_COLOR: Force colored output even when not in a terminal
use firo_logger::init_from_env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
init_from_env()?;
log_info!("Logger configured from environment");
Ok(())
}
Configuration Builder
use firo_logger::{LoggerConfig, LogLevel, OutputFormat, RotationFrequency};
let config = LoggerConfig::builder()
// Basic settings
.level(LogLevel::Info)
.format(OutputFormat::Text)
// Console output
.console(true)
.colors(true)
.use_stderr(true) // Use stderr for errors/warnings
// File output
.file("logs/app.log")
.rotate_by_size(50 * 1024 * 1024, 10) // 50MB, keep 10 files
.rotate_by_time(RotationFrequency::Daily, 7) // Daily rotation, keep 7 days
// Performance
.async_logging(1000) // Enable async with 1000 message buffer
// Metadata and context
.include_caller(true)
.include_thread(true)
.datetime_format("%Y-%m-%d %H:%M:%S%.3f")
.metadata("service", "api-server")
.metadata("version", env!("CARGO_PKG_VERSION"))
// Module-specific filtering
.module_filter("hyper", LogLevel::Warning)
.module_filter("my_app::debug", LogLevel::Debug)
.build();
Logging Macros
Basic Logging
log_error!("Database connection failed: {}", error);
log_warning!("Deprecated API used: {}", api_name);
log_info!("User {} logged in", username);
log_success!("Payment processed: ${}", amount);
log_debug!("Processing request: {:?}", request);
Advanced Logging
Structured Logging with Metadata
use firo_logger::{log_with_metadata, LogLevel};
log_with_metadata!(
LogLevel::Info,
"User login",
"user_id" => "12345",
"ip_address" => "192.168.1.100",
"user_agent" => "Mozilla/5.0...",
"session_id" => session.id()
);
Conditional Logging
use firo_logger::{log_if, LogLevel};
let debug_mode = std::env::var("DEBUG").is_ok();
log_if!(debug_mode, LogLevel::Debug, "Debug mode is enabled");
let should_trace = user.is_admin();
log_if!(should_trace, LogLevel::Info, "Admin user {} performed action", user.name);
Rate-Limited Logging
use firo_logger::{log_rate_limited, LogLevel};
use std::time::Duration;
// In a high-frequency loop
for i in 0..10000 {
// This will only log once per second maximum
log_rate_limited!(
Duration::from_secs(1),
LogLevel::Info,
"Processing item {}", i
);
}
Function Tracing
use firo_logger::trace_function;
fn process_payment(amount: f64, user_id: u64) -> Result<(), PaymentError> {
trace_function!("process_payment", amount, user_id);
// Function implementation...
// Entry and exit will be automatically logged
Ok(())
}
Performance Timing
use firo_logger::{time_block, LogLevel};
let result = time_block!(LogLevel::Info, "Database query", {
// Your expensive operation here
database.complex_query().await
});
Assert with Logging
use firo_logger::log_assert;
let user_id = get_user_id();
log_assert!(user_id > 0, "User ID must be positive, got {}", user_id);
// Debug-only assertions
log_debug_assert!(expensive_invariant_check(), "Invariant violated");
Output Formats
Text Format (Default)
2024-08-14 09:33:45.123 [ ERROR]: Database connection failed: timeout
2024-08-14 09:33:45.124 [WARNING]: Deprecated API endpoint used
2024-08-14 09:33:45.125 [ INFO]: User alice logged in
2024-08-14 09:33:45.126 [SUCCESS]: Payment of $49.99 processed
2024-08-14 09:33:45.127 [ DEBUG]: Request processed in 23ms
JSON Format
{"timestamp":"2024-08-14T09:33:45.123Z","level":"ERROR","message":"Database connection failed: timeout","module":"myapp::db","caller":{"file":"src/db.rs","line":42}}
{"timestamp":"2024-08-14T09:33:45.124Z","level":"INFO","message":"User alice logged in","metadata":{"user_id":"12345","ip":"192.168.1.1"}}
Plain Format
2024-08-14 09:33:45 [ERROR]: Database connection failed: timeout
2024-08-14 09:33:45 [INFO]: User alice logged in
File Rotation
Size-Based Rotation
let config = LoggerConfig::builder()
.file("app.log")
.rotate_by_size(10 * 1024 * 1024, 5) // 10MB files, keep 5
.build();
Generated files:
app.log(current)app.log.1628934123(backup)app.log.1628934100(backup)- etc.
Time-Based Rotation
use firo_logger::RotationFrequency;
let config = LoggerConfig::builder()
.file("app.log")
.rotate_by_time(RotationFrequency::Daily, 7) // Daily rotation, keep 7 days
.build();
Generated files:
app.log(current)app.log.2024-08-13(yesterday)app.log.2024-08-12(day before)- etc.
Async Logging
For high-performance applications, enable async logging:
let config = LoggerConfig::builder()
.async_logging(10000) // Buffer up to 10,000 messages
.build();
// Logging calls return immediately, processing happens in background
for i in 0..1000000 {
log_info!("Processing item {}", i)?; // Very fast, non-blocking
}
Integration with log Crate
Enable the log feature and use firo_logger as a backend:
[dependencies]
firo_logger = { version = "0.3.0", features = ["log"] }
log = "0.4"
use firo_logger::log_integration::init_with_log;
fn main() -> Result<(), Box<dyn std::error::Error>> {
init_with_log()?;
// Now you can use the standard log macros
log::info!("This works with firo_logger!");
log::error!("Error handling through standard log crate");
Ok(())
}
Performance
firo_logger is designed for high performance:
- Async logging: Non-blocking log calls with background processing
- Buffered I/O: Configurable buffer sizes for file output
- Lazy formatting: Log messages are only formatted if they pass level filters
- Zero allocation: Many operations avoid memory allocation
- Lock-free paths: Optimized for concurrent access
Benchmarks show firo_logger can handle:
- 1M+ logs/second in async mode
- Sub-microsecond latency for filtered-out messages
- Minimal memory overhead
Migration from v0.2.x
The new version is fully backwards compatible. Your existing code will continue to work:
// Old API still works
use firo_logger::legacy::{Logger, LogLevel};
Logger::log(format_args!("Still works!"));
Logger::error(format_args!("Error handling"));
But we recommend migrating to the new API:
// New API
use firo_logger::{init_default, log_info, log_error};
init_default()?;
log_info!("Much better!")?;
log_error!("Improved error handling")?;
Examples
See the examples/ directory for more examples:
# Basic usage
cargo run --example basic_usage
# Advanced features
cargo run --example advanced_features
# Performance testing
cargo run --example performance_test --release
Features Flags
colors(default): ANSI color supportjson(default): JSON output format supportasync(default): Async logging supportlog: Integration with the standardlogcratesyslog: Syslog output support (future feature)
# Minimal build without async support
[dependencies]
firo_logger = { version = "0.3.0", default-features = false, features = ["colors"] }
Development & Release
Local Testing
Before pushing changes, run the comprehensive test suite:
# Run all CI checks locally
./test-local.sh
# Individual checks
cargo fmt -- --check
cargo clippy --all-features -- -D warnings
cargo test --all-features
cargo doc --no-deps --all-features
Automated Release
The project includes an automated release script that handles version bumping, testing, and publishing:
# Interactive mode - asks which increment type
./release.sh
# Direct version increment
./release.sh patch # 1.0.0 → 1.0.1 (bug fixes)
./release.sh minor # 1.0.0 → 1.1.0 (new features)
./release.sh major # 1.0.0 → 2.0.0 (breaking changes)
# Preview changes without executing
./release.sh --dry-run
# Show help
./release.sh --help
What the Release Script Does:
-
🔍 Pre-flight checks:
- Validates git repository state
- Ensures on main branch with clean working directory
- Verifies remote connectivity
- Checks for existing tags
-
🧪 Quality assurance:
- Runs comprehensive test suite
- Validates code formatting and linting
- Ensures documentation builds
-
📝 Version management:
- Updates
Cargo.tomlversion - Updates
CHANGELOG.mdwith release date - Creates git commit and annotated tag
- Updates
-
🚀 Publishing:
- Pushes changes and tags to remote
- Triggers GitHub Actions for automated crates.io publishing
Safety Features:
- Error recovery: Automatically reverts changes if something fails
- Confirmation prompts: Asks before making destructive changes
- Comprehensive validation: Multiple safety checks at each step
- Dry-run mode: Preview all changes before executing
GitHub Actions CI/CD
The project uses GitHub Actions for continuous integration and deployment:
- CI Pipeline: Runs on every push/PR with comprehensive testing
- Release Pipeline: Automatically publishes to crates.io when tags are created
- Dependency Updates: Weekly automated dependency updates with auto-merge
To set up automated publishing:
- Get a crates.io API token from crates.io/settings/tokens
- Add it as
CARGO_REGISTRY_TOKENin GitHub repo Settings → Secrets → Actions
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Development Workflow:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run local tests (
./test-local.sh) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
v0.3.0 (2024-08-14)
- 🎉 Major rewrite with backwards compatibility
- ✨ New Features:
- Structured logging with JSON support
- File rotation (size and time-based)
- Async logging for high performance
- Module-specific log level filtering
- Advanced macros (rate limiting, timing, tracing)
- Environment variable configuration
- Statistics and monitoring
- Integration with standard
logcrate
- 🚀 Performance: Up to 10x faster than v0.2.x
- 🔧 API: New builder pattern for configuration
- 📚 Documentation: Comprehensive examples and guides
v0.2.1 (Previous)
- Basic colored console logging
- Simple file output
- Basic log levels
Acknowledgments
- Inspired by popular logging libraries like
env_logger,slog, andtracing - Built with performance and usability in mind
- Thanks to the Rust community for feedback and contributions
Dependencies
~2–3.5MB
~63K SLoC