# firo_logger
[](https://crates.io/crates/firo_logger)
[](https://docs.rs/firo_logger)
[](https://opensource.org/licenses/MIT)
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`:
```toml
[dependencies]
firo_logger = "0.3.0"
```
### Basic Usage
```rust
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
```rust
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 path
- `FIRO_LOG_FORMAT`: Set output format (`text`, `json`, `plain`)
- `NO_COLOR`: Disable colored output
- `FORCE_COLOR`: Force colored output even when not in a terminal
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```json
{"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
```rust
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
```rust
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:
```rust
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:
```toml
[dependencies]
firo_logger = { version = "0.3.0", features = ["log"] }
log = "0.4"
```
```rust
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:
```rust
// 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:
```rust
// 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:
```bash
# 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 support
- `json` (default): JSON output format support
- `async` (default): Async logging support
- `log`: Integration with the standard `log` crate
- `syslog`: Syslog output support (future feature)
```toml
# 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:
```bash
# 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:
```bash
# 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:
1. **๐ Pre-flight checks:**
- Validates git repository state
- Ensures on main branch with clean working directory
- Verifies remote connectivity
- Checks for existing tags
2. **๐งช Quality assurance:**
- Runs comprehensive test suite
- Validates code formatting and linting
- Ensures documentation builds
3. **๐ Version management:**
- Updates `Cargo.toml` version
- Updates `CHANGELOG.md` with release date
- Creates git commit and annotated tag
4. **๐ 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:
1. Get a crates.io API token from [crates.io/settings/tokens](https://crates.io/settings/tokens)
2. Add it as `CARGO_REGISTRY_TOKEN` in 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:
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Run local tests (`./test-local.sh`)
5. Commit your changes (`git commit -m 'Add amazing feature'`)
6. Push to the branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request
## License
This project is licensed under the MIT License - see the [LICENSE](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 `log` crate
- ๐ **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`, and `tracing`
- Built with performance and usability in mind
- Thanks to the Rust community for feedback and contributions