259 lines
7.0 KiB
Markdown
259 lines
7.0 KiB
Markdown
# Hero Logger
|
|
|
|
A hierarchical logging system for the Hero project that provides system-level and per-job logging with complete isolation using the `tracing` ecosystem.
|
|
|
|
## Features
|
|
|
|
- **Hierarchical Organization**: Physical separation of logs by component and job
|
|
- **System Logger**: Global logging for all non-job-specific events
|
|
- **Per-Job Logger**: Isolated logging for individual job execution
|
|
- **Hourly Rotation**: Automatic log file rotation every hour
|
|
- **Rhai Integration**: Capture Rhai script `print()` and `debug()` calls
|
|
- **High Performance**: Async logging with efficient filtering
|
|
- **Structured Logging**: Rich context and metadata support
|
|
|
|
## Architecture
|
|
|
|
The logging system uses a hybrid approach with two main components:
|
|
|
|
### System Logger (Global)
|
|
- Long-lived logger initialized at application startup
|
|
- Routes logs to different files based on tracing targets
|
|
- Supports multiple components simultaneously
|
|
|
|
### Per-Job Logger (Dynamic)
|
|
- Created on-demand for each job execution
|
|
- Provides complete isolation for job-specific logs
|
|
- Automatically disposed after job completion
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
logs/
|
|
├── supervisor/ # System logs for supervisor
|
|
│ └── 2025-08-06-11.log
|
|
└── actor/
|
|
├── osis/
|
|
│ ├── 2025-08-06-11.log # General OSIS actor logs
|
|
│ ├── job-a1b2c3d4/ # Job-specific logs
|
|
│ │ └── 2025-08-06-11.log
|
|
│ └── job-9a8b7c6d/
|
|
│ └── 2025-08-06-12.log
|
|
└── sal/
|
|
├── 2025-08-06-13.log # General SAL actor logs
|
|
└── job-f1e2d3c4/
|
|
└── 2025-08-06-13.log
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### 1. Initialize System Logger
|
|
|
|
```rust
|
|
use hero_logger;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Define your system components
|
|
let components = vec![
|
|
"supervisor".to_string(),
|
|
"osis_actor".to_string(),
|
|
"sal_actor".to_string(),
|
|
];
|
|
|
|
// Initialize the system logger
|
|
let _guards = hero_logger::init_system_logger("logs", &components)?;
|
|
|
|
// Now you can use tracing macros with targets
|
|
tracing::info!(target: "supervisor", "System started");
|
|
tracing::info!(target: "osis_actor", "Actor ready");
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
### 2. Per-Job Logging
|
|
|
|
```rust
|
|
use hero_logger::create_job_logger;
|
|
use tracing::subscriber::with_default;
|
|
|
|
async fn process_job(job_id: &str, actor_type: &str) {
|
|
// Create job-specific logger
|
|
let job_logger = create_job_logger("logs", actor_type, job_id)?;
|
|
|
|
// Execute job within logging context
|
|
with_default(job_logger, || {
|
|
tracing::info!(target: "osis_actor", "Job {} started", job_id);
|
|
|
|
// All tracing calls here go to the job-specific log
|
|
tracing::debug!(target: "osis_actor", "Processing data...");
|
|
tracing::info!(target: "osis_actor", "Job {} completed", job_id);
|
|
});
|
|
}
|
|
```
|
|
|
|
### 3. Rhai Script Integration
|
|
|
|
```rust
|
|
use hero_logger::rhai_integration::configure_rhai_logging;
|
|
use rhai::Engine;
|
|
|
|
fn setup_rhai_engine() -> Engine {
|
|
let mut engine = Engine::new();
|
|
|
|
// Configure Rhai to capture print/debug calls
|
|
configure_rhai_logging(&mut engine, "osis_actor");
|
|
|
|
engine
|
|
}
|
|
|
|
// Now Rhai scripts can use print() and debug()
|
|
let script = r#"
|
|
print("Hello from Rhai!");
|
|
debug("Debug information");
|
|
42
|
|
"#;
|
|
|
|
let result = engine.eval::<i64>(script)?;
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### Core Functions
|
|
|
|
#### `init_system_logger(logs_root, components)`
|
|
Initialize the global system logger with component-based filtering.
|
|
|
|
**Parameters:**
|
|
- `logs_root`: Root directory for log files
|
|
- `components`: List of component names for dedicated logging
|
|
|
|
**Returns:** Vector of `WorkerGuard`s that must be kept alive
|
|
|
|
#### `create_job_logger(logs_root, actor_type, job_id)`
|
|
Create a per-job logger for isolated logging.
|
|
|
|
**Parameters:**
|
|
- `logs_root`: Root directory for log files
|
|
- `actor_type`: Type of actor (e.g., "osis", "sal")
|
|
- `job_id`: Unique job identifier
|
|
|
|
**Returns:** Boxed subscriber for use with `with_default()`
|
|
|
|
### Rhai Integration
|
|
|
|
#### `configure_rhai_logging(engine, target)`
|
|
Configure a Rhai engine to capture print/debug output.
|
|
|
|
#### `add_custom_logging_functions(engine, target)`
|
|
Add custom logging functions (`log_info`, `log_debug`, etc.) to Rhai.
|
|
|
|
#### `create_logging_enabled_engine(target, include_custom)`
|
|
Create a new Rhai engine with full logging integration.
|
|
|
|
### Utilities
|
|
|
|
#### `ensure_log_directories(logs_root, components)`
|
|
Ensure the log directory structure exists.
|
|
|
|
#### `extract_actor_type(component)`
|
|
Extract actor type from component name.
|
|
|
|
#### `cleanup_old_logs(directory, pattern, max_age_days)`
|
|
Clean up old log files based on age.
|
|
|
|
## Configuration
|
|
|
|
### Log Levels
|
|
The system supports standard tracing log levels:
|
|
- `ERROR`: Critical errors
|
|
- `WARN`: Warning messages
|
|
- `INFO`: Informational messages
|
|
- `DEBUG`: Debug information
|
|
- `TRACE`: Detailed trace information
|
|
|
|
### Environment Variables
|
|
- `RUST_LOG`: Set log level filtering (e.g., `RUST_LOG=debug`)
|
|
|
|
### File Rotation
|
|
- **Hourly**: Default rotation every hour
|
|
- **Daily**: Optional daily rotation
|
|
- **Never**: Single file (no rotation)
|
|
|
|
## Examples
|
|
|
|
### Basic Usage
|
|
```bash
|
|
cargo run --example logging_demo
|
|
```
|
|
|
|
### Integration with Actor System
|
|
```rust
|
|
// In your actor implementation
|
|
async fn process_job(&self, job: &Job) {
|
|
let job_logger = hero_logger::create_job_logger(
|
|
"logs",
|
|
&self.actor_type,
|
|
&job.id
|
|
).unwrap();
|
|
|
|
let job_task = async move {
|
|
tracing::info!(target: &self.actor_type, "Job processing started");
|
|
|
|
// Configure Rhai engine for this job
|
|
let mut engine = Engine::new();
|
|
hero_logger::rhai_integration::configure_rhai_logging(
|
|
&mut engine,
|
|
&self.actor_type
|
|
);
|
|
|
|
// Execute Rhai script - print/debug calls captured
|
|
let result = engine.eval::<String>(&job.script)?;
|
|
|
|
tracing::info!(target: &self.actor_type, "Job finished: {}", result);
|
|
Ok(result)
|
|
};
|
|
|
|
// Execute with job-specific logging
|
|
tracing::subscriber::with_default(job_logger, job_task).await;
|
|
}
|
|
```
|
|
|
|
## Performance Considerations
|
|
|
|
- **Async Logging**: All file I/O is asynchronous
|
|
- **Efficient Filtering**: Target-based filtering minimizes overhead
|
|
- **Memory Usage**: Per-job loggers are short-lived and automatically cleaned up
|
|
- **File Handles**: Automatic rotation prevents excessive file handle usage
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
1. **Logs not appearing**: Ensure `WorkerGuard`s are kept alive
|
|
2. **Permission errors**: Check write permissions on log directory
|
|
3. **Missing directories**: Use `ensure_log_directories()` before logging
|
|
4. **Rhai output not captured**: Verify `configure_rhai_logging()` is called
|
|
|
|
### Debug Mode
|
|
Enable debug logging to see internal logger operations:
|
|
```bash
|
|
RUST_LOG=hero_logger=debug cargo run
|
|
```
|
|
|
|
## Testing
|
|
|
|
Run the test suite:
|
|
```bash
|
|
cargo test
|
|
```
|
|
|
|
Run the demo example:
|
|
```bash
|
|
cargo run --example logging_demo
|
|
```
|
|
|
|
## License
|
|
|
|
This project is part of the Hero ecosystem and follows the same licensing terms. |