diff --git a/README.md b/README.md index 52db3602..d587a592 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,8 @@ cargo install --path . torrust-tracker-deployer ``` +The application includes comprehensive logging with configurable format, output mode, and directory. See **[๐Ÿ“– Logging Guide](docs/user-guide/logging.md)** for details on logging configuration options. + #### ๐Ÿ”ง Development Tasks This project includes convenient scripts for common development tasks: diff --git a/docs/contributing/logging-guide.md b/docs/contributing/logging-guide.md index e4c69374..1de8cfa8 100644 --- a/docs/contributing/logging-guide.md +++ b/docs/contributing/logging-guide.md @@ -2,6 +2,63 @@ This guide explains the structured logging implementation in the Torrust Tracker Deployer project, which uses hierarchical structured logging. +## Main Application Logging + +The main CLI application (`src/main.rs` โ†’ `src/app.rs`) initializes logging at startup with user-configurable options. This provides a consistent logging infrastructure for all operations. + +### Application Logging Setup + +The main application uses `LoggingBuilder` with CLI arguments for configuration: + +```rust +// src/app.rs +use torrust_tracker_deployer_lib::logging::{LogFormat, LogOutput, LoggingBuilder}; + +pub fn run() { + let cli = Cli::parse(); + + // Initialize logging FIRST before any other logic + LoggingBuilder::new(&cli.log_dir) + .with_format(cli.log_format) + .with_output(cli.log_output) + .init(); + + // Log startup with context + info!( + app = "torrust-tracker-deployer", + version = env!("CARGO_PKG_VERSION"), + log_dir = %cli.log_dir.display(), + log_format = ?cli.log_format, + log_output = ?cli.log_output, + "Application started" + ); + + // ... application logic ... + + info!("Application finished"); +} +``` + +### User-Facing Configuration + +Users can configure logging via CLI arguments: + +```bash +# Default (production): file-only, compact format +torrust-tracker-deployer + +# Development: stderr output, pretty format +torrust-tracker-deployer --log-format pretty --log-output file-and-stderr + +# Custom log directory +torrust-tracker-deployer --log-dir /var/log/deployer + +# JSON format for log aggregation +torrust-tracker-deployer --log-format json +``` + +See [User Guide: Logging](../user-guide/logging.md) for complete user documentation. + ## JSON Output Format When using `logging::init_json()` or `LogFormat::Json`, logs are output in JSON format suitable for log aggregation: diff --git a/docs/user-guide/logging.md b/docs/user-guide/logging.md new file mode 100644 index 00000000..20e437e2 --- /dev/null +++ b/docs/user-guide/logging.md @@ -0,0 +1,411 @@ +# Logging Guide + +This guide explains how to configure and use logging in the Torrust Tracker Deployer. + +## Overview + +The application provides comprehensive structured logging for observability and troubleshooting. All operations are logged to persistent log files, allowing you to review what happened even after the application has finished running. + +### Key Principles + +- **Always persistent**: Logs are always written to files for post-mortem analysis +- **Configurable output**: Choose between file-only (production) or file+stderr (development) +- **Multiple formats**: Pretty, JSON, or compact formatting to suit your needs +- **Environment-based filtering**: Use `RUST_LOG` to control log verbosity + +## Quick Start + +### Default Behavior (Production) + +By default, the application uses production-safe settings: + +```bash +torrust-tracker-deployer +``` + +This configuration: + +- Writes logs to `./data/logs/log.txt` +- Uses **compact** format (space-efficient, readable) +- **File-only** output (no stderr pollution) +- **Info** level logging (controlled by `RUST_LOG`) + +### Development Mode + +For development and troubleshooting, enable stderr output: + +```bash +torrust-tracker-deployer --log-output file-and-stderr +``` + +This shows log events in real-time on your terminal while still writing to the log file. + +### Pretty Format for Debugging + +For maximum readability during development: + +```bash +torrust-tracker-deployer --log-format pretty --log-output file-and-stderr +``` + +## Configuration Options + +### Log Format (`--log-format`) + +Controls how log entries are formatted: + +#### Compact (Default) + +Space-efficient single-line format, ideal for production: + +```bash +torrust-tracker-deployer --log-format compact +``` + +Example output: + +```text +2025-10-15T12:39:22.793955Z INFO torrust_tracker_deployer::app: Application started app="torrust-tracker-deployer" version="0.1.0" +``` + +#### Pretty + +Multi-line format with visual structure, ideal for development: + +```bash +torrust-tracker-deployer --log-format pretty --log-output file-and-stderr +``` + +Example output: + +```text + 2025-10-15T12:40:36.097921Z INFO torrust_tracker_deployer::app: Application started, app: "torrust-tracker-deployer", version: "0.1.0" + at src/app.rs:69 +``` + +#### JSON + +Machine-readable format for log aggregation systems: + +```bash +torrust-tracker-deployer --log-format json +``` + +Example output: + +```json +{"timestamp":"2025-10-15T12:42:34.178335Z","level":"INFO","fields":{"message":"Application started","app":"torrust-tracker-deployer","version":"0.1.0"},"target":"torrust_tracker_deployer::app"} +``` + +### Log Output (`--log-output`) + +Controls where logs are written: + +#### File Only (Default) + +Production mode - logs written only to file: + +```bash +torrust-tracker-deployer --log-output file-only +``` + +- โœ… Clean terminal output (no log noise) +- โœ… All logs captured in persistent file +- โœ… Suitable for production deployments + +#### File and Stderr + +Development mode - logs written to both file and stderr: + +```bash +torrust-tracker-deployer --log-output file-and-stderr +``` + +- โœ… Real-time log visibility on terminal +- โœ… All logs still captured in persistent file +- โœ… Suitable for development and troubleshooting + +### Log Directory (`--log-dir`) + +Specifies where log files should be written: + +```bash +# Use custom directory +torrust-tracker-deployer --log-dir /var/log/deployer + +# Use relative path +torrust-tracker-deployer --log-dir ./custom-logs + +# Use deeply nested directory (created automatically) +torrust-tracker-deployer --log-dir /tmp/app/logs/production +``` + +The log file is always named `log.txt` inside the specified directory. Parent directories are created automatically if they don't exist. + +## Log Levels + +Control log verbosity using the `RUST_LOG` environment variable: + +### Info Level (Default) + +Standard operational logging: + +```bash +torrust-tracker-deployer +# or explicitly +RUST_LOG=info torrust-tracker-deployer +``` + +Shows: + +- Application startup/shutdown +- Major operations and milestones +- Errors and warnings + +### Debug Level + +Detailed diagnostic information: + +```bash +RUST_LOG=debug torrust-tracker-deployer --log-output file-and-stderr +``` + +Shows everything from Info level, plus: + +- Internal operation details +- State transitions +- Configuration values + +### Trace Level + +Maximum verbosity for deep debugging: + +```bash +RUST_LOG=trace torrust-tracker-deployer --log-output file-and-stderr +``` + +Shows everything from Debug level, plus: + +- Function entry/exit +- Low-level details +- All internal operations + +โš ๏ธ **Warning**: Trace level generates significant log volume. Use only for specific debugging scenarios. + +### Module-Specific Filtering + +Filter logs by module or crate: + +```bash +# Only logs from torrust_tracker_deployer +RUST_LOG=torrust_tracker_deployer=debug torrust-tracker-deployer + +# Multiple modules with different levels +RUST_LOG=torrust_tracker_deployer=debug,ansible=trace torrust-tracker-deployer + +# Exclude specific modules +RUST_LOG=debug,tokio=warn torrust-tracker-deployer +``` + +## Common Scenarios + +### Scenario 1: Production Deployment + +Production-safe defaults with minimal configuration: + +```bash +torrust-tracker-deployer +``` + +- Logs to `./data/logs/log.txt` +- Compact format +- File-only output +- Info level + +### Scenario 2: Development Work + +Real-time log visibility with readable format: + +```bash +torrust-tracker-deployer --log-format pretty --log-output file-and-stderr +``` + +- Logs to `./data/logs/log.txt` and stderr +- Pretty format +- Info level (increase with RUST_LOG if needed) + +### Scenario 3: Troubleshooting Issues + +Maximum verbosity for debugging: + +```bash +RUST_LOG=debug torrust-tracker-deployer --log-format pretty --log-output file-and-stderr +``` + +- Debug level logging +- Pretty format for readability +- Real-time visibility on terminal +- Persistent file for later analysis + +### Scenario 4: Log Aggregation + +JSON format for external monitoring systems: + +```bash +torrust-tracker-deployer --log-format json --log-dir /var/log/deployer +``` + +- JSON format for machine parsing +- Custom log directory +- File-only output (monitor the file externally) + +### Scenario 5: CI/CD Pipeline + +Visible logs for automated testing: + +```bash +torrust-tracker-deployer --log-output file-and-stderr +``` + +- Compact format (space-efficient) +- Stderr output (captured by CI system) +- Persistent file (artifact for later review) + +## Log File Management + +### Log File Location + +The log file is created at: + +```text +/log.txt +``` + +Default: `./data/logs/log.txt` (relative to working directory) + +### Append Mode + +Logs are **appended** to existing log files, not overwritten: + +```bash +# First run +torrust-tracker-deployer +# Creates ./data/logs/log.txt with entries + +# Second run +torrust-tracker-deployer +# Appends new entries to ./data/logs/log.txt +``` + +This allows you to: + +- โœ… Track multiple runs in a single file +- โœ… Preserve historical logs +- โœ… Analyze trends over time + +### Log Rotation + +โš ๏ธ **Note**: Automatic log rotation is not currently implemented. + +For production use, consider: + +- External log rotation tools (logrotate) +- Regular manual cleanup +- Monitoring log file size + +## Error Handling + +### Log Directory Creation + +The application automatically creates the log directory if it doesn't exist: + +```bash +# Non-existent directory is created automatically +torrust-tracker-deployer --log-dir /tmp/new/nested/logs +``` + +### Permission Issues + +If the log directory cannot be created due to permission issues, the application will exit with an error: + +```bash +torrust-tracker-deployer --log-dir /root/logs + +# Output: +# thread 'main' panicked at src/logging.rs:260:9: +# Failed to create log directory: /root/logs - check filesystem permissions +``` + +**This behavior is intentional** - logging is critical for observability, and the application cannot function properly without it. + +**Solutions:** + +- Use a writable directory +- Adjust filesystem permissions +- Run with appropriate user privileges + +## Best Practices + +### Development + +1. **Use stderr output** for real-time visibility: + + ```bash + torrust-tracker-deployer --log-output file-and-stderr + ``` + +2. **Use pretty format** for readability: + + ```bash + torrust-tracker-deployer --log-format pretty --log-output file-and-stderr + ``` + +3. **Increase verbosity** when debugging: + + ```bash + RUST_LOG=debug torrust-tracker-deployer --log-output file-and-stderr + ``` + +### Production + +1. **Use default settings** for production: + + ```bash + torrust-tracker-deployer + ``` + +2. **Consider JSON format** for log aggregation: + + ```bash + torrust-tracker-deployer --log-format json + ``` + +3. **Use absolute paths** for log directories: + + ```bash + torrust-tracker-deployer --log-dir /var/log/torrust-tracker-deployer + ``` + +4. **Monitor log file size** and implement rotation + +### CI/CD + +1. **Enable stderr output** for CI system capture: + + ```bash + torrust-tracker-deployer --log-output file-and-stderr + ``` + +2. **Use compact format** for space efficiency: + + ```bash + torrust-tracker-deployer --log-format compact --log-output file-and-stderr + ``` + +3. **Archive log files** as build artifacts + +## Additional Resources + +- [Contributing: Logging Guide](../contributing/logging-guide.md) - How to add logging to code +- [Development Principles](../development-principles.md) - Observability principles +- [User Output vs Logging Separation](../research/UX/user-output-vs-logging-separation.md) - Design rationale diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 00000000..1d54198c --- /dev/null +++ b/src/app.rs @@ -0,0 +1,104 @@ +//! Main application module for the Torrust Tracker Deployer CLI +//! +//! This module contains the CLI structure and main application logic. +//! It initializes logging and handles the application lifecycle. + +use clap::Parser; +use std::path::PathBuf; +use tracing::info; + +use torrust_tracker_deployer_lib::logging::{LogFormat, LogOutput, LoggingBuilder}; + +/// Command-line interface for Torrust Tracker Deployer +#[derive(Parser)] +#[command(name = "torrust-tracker-deployer")] +#[command(about = "Automated deployment infrastructure for Torrust Tracker")] +#[command(version)] +#[allow(clippy::struct_field_names)] // CLI arguments intentionally share 'log_' prefix for clarity +pub struct Cli { + /// Logging format (default: compact) + /// + /// - pretty: Pretty-printed output for development + /// - json: JSON output for production environments + /// - compact: Compact output for minimal verbosity + #[arg(long, value_enum, default_value = "compact", global = true)] + pub log_format: LogFormat, + + /// Log output mode (default: file-only for production) + /// + /// - file-only: Write logs to file only (production mode) + /// - file-and-stderr: Write logs to both file and stderr (development/testing mode) + #[arg(long, value_enum, default_value = "file-only", global = true)] + pub log_output: LogOutput, + + /// Log directory (default: ./data/logs) + /// + /// Directory where log files will be written. The log file will be + /// named 'log.txt' inside this directory. Parent directories will be + /// created automatically if they don't exist. + /// + /// Note: If the directory cannot be created due to filesystem permissions, + /// the application will exit with an error. Logging is critical for + /// observability and the application cannot function without it. + #[arg(long, default_value = "./data/logs", global = true)] + pub log_dir: PathBuf, +} + +/// Main application entry point +/// +/// This function initializes logging, displays information to the user, +/// and prepares the application for future command processing. +/// +/// # Panics +/// +/// This function will panic if: +/// - Log directory cannot be created (filesystem permissions issue) +/// - Logging initialization fails (usually means it was already initialized) +/// +/// Both panics are intentional as logging is critical for observability. +pub fn run() { + let cli = Cli::parse(); + + // Clone values for logging before moving them + let log_format = cli.log_format.clone(); + let log_output = cli.log_output; + let log_dir = cli.log_dir.clone(); + + // Initialize logging FIRST before any other logic + LoggingBuilder::new(&cli.log_dir) + .with_format(cli.log_format) + .with_output(cli.log_output) + .init(); + + // Log startup event with configuration details + info!( + app = "torrust-tracker-deployer", + version = env!("CARGO_PKG_VERSION"), + log_dir = %log_dir.display(), + log_format = ?log_format, + log_output = ?log_output, + "Application started" + ); + + // Display info to user (keep existing behavior for now) + println!("๐Ÿ—๏ธ Torrust Tracker Deployer"); + println!("========================="); + println!(); + println!("This repository provides automated deployment infrastructure for Torrust tracker projects."); + println!("The infrastructure includes VM provisioning with OpenTofu and configuration"); + println!("management with Ansible playbooks."); + println!(); + println!("๐Ÿ“‹ Getting Started:"); + println!(" Please follow the instructions in the README.md file to:"); + println!(" 1. Set up the required dependencies (OpenTofu, Ansible, LXD)"); + println!(" 2. Provision the deployment infrastructure"); + println!(" 3. Deploy and configure the services"); + println!(); + println!("๐Ÿงช Running E2E Tests:"); + println!(" Use the e2e tests binaries to run end-to-end tests:"); + println!(" cargo e2e-provision && cargo e2e-config"); + println!(); + println!("๐Ÿ“– For detailed instructions, see: README.md"); + + info!("Application finished"); +} diff --git a/src/main.rs b/src/main.rs index 64069cd4..024d1578 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,10 @@ //! Main binary entry point for Torrust Tracker Deployer. //! -//! This binary provides a simple information display about the deployment infrastructure. +//! This binary provides the main CLI interface for the deployment infrastructure. +//! All application logic is contained in the `app` module. + +mod app; fn main() { - println!("๐Ÿ—๏ธ Torrust Tracker Deployer"); - println!("========================="); - println!(); - println!("This repository provides automated deployment infrastructure for Torrust tracker projects."); - println!("The infrastructure includes VM provisioning with OpenTofu and configuration"); - println!("management with Ansible playbooks."); - println!(); - println!("๐Ÿ“‹ Getting Started:"); - println!(" Please follow the instructions in the README.md file to:"); - println!(" 1. Set up the required dependencies (OpenTofu, Ansible, LXD)"); - println!(" 2. Provision the deployment infrastructure"); - println!(" 3. Deploy and configure the services"); - println!(); - println!("๐Ÿงช Running E2E Tests:"); - println!(" Use the e2e tests binaries to run end-to-end tests:"); - println!(" cargo e2e-provision && cargo e2e-config"); - println!(); - println!("๐Ÿ“– For detailed instructions, see: README.md"); + app::run(); }