Skip to content

Implement structured logging with credential protection #65

@unclesp1d3r

Description

@unclesp1d3r

Implement Structured Logging Infrastructure with Credential Protection - Task #11

🎯 Epic Context

📊 Current State Analysis

Existing Infrastructure:

  • ✅ CLI framework with --verbose and --quiet flags (unused)
  • ✅ Error handling patterns established
  • ✅ URL redaction utility in src/tls.rs (redact_url function)
  • No logging dependencies - missing tracing ecosystem
  • No structured logging implementation
  • Verbose/quiet flags not connected to any logging

Security Context:

  • Must comply with WARP.md credential protection requirements
  • Existing redact_url() function available for DATABASE_URL sanitization
  • Zero credential leakage tolerance

🎯 Requirements Implementation

Requirement 7.1: Structured JSON Logging

  • Current: Plain stdout output only
  • Target: JSON-structured logs via tracing crate
  • Trigger: --verbose flag activation

Requirement 7.2: Credential Protection

  • Current: No logging, so no risk
  • Target: Integrate existing redact_url() function
  • Scope: DATABASE_URL, passwords, sensitive connection strings

Requirement 7.3: Multi-level Verbosity

  • Current: Single --verbose boolean flag
  • Target: Progressive levels based on flag count (-v, -vv, -vvv)
  • Mapping: 1=info, 2=debug, 3+=trace

Requirement 7.4: Quiet Mode

  • Current: Basic --quiet flag exists
  • Target: Suppress all output except errors
  • Behavior: Override verbose settings when active

🚀 Proposed Implementation

Phase 1: Dependencies & Infrastructure

# Cargo.toml additions
[dependencies]
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["json", "env-filter", "time"] }
serde = { version = "1.0", features = ["derive"] }

Phase 2: Core Logging Module (src/logging.rs)

use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, fmt};
use crate::tls::redact_url;

#[derive(Debug, Clone)]
pub struct LoggingConfig {
    pub verbose_count: u8,
    pub quiet: bool,
}

impl LoggingConfig {
    pub fn from_args(verbose_count: u8, quiet: bool) -> Self {
        Self { verbose_count, quiet }
    }
    
    pub fn init_structured_logging(&self) -> Result<(), Box<dyn std::error::Error>> {
        let level = if self.quiet {
            "error"
        } else {
            match self.verbose_count {
                0 => "warn",
                1 => "info", 
                2 => "debug",
                _ => "trace",
            }
        };
        
        let filter = EnvFilter::new(format!("gold_digger={}", level));
        
        tracing_subscriber::registry()
            .with(fmt::layer()
                .json()
                .with_current_span(false)
                .with_span_list(true))
            .with(filter)
            .init();
            
        tracing::info!(
            version = env!("CARGO_PKG_VERSION"),
            verbose_count = self.verbose_count,
            quiet = self.quiet,
            "Structured logging initialized"
        );
        
        Ok(())
    }
}

// Credential-safe logging macros
#[macro_export]
macro_rules! log_database_url {
    ($url:expr) => {
        tracing::debug!(database_url = %crate::tls::redact_url($url), "Database connection configured");
    };
}

Phase 3: Integration Points

Main Application (src/main.rs):

mod logging;
use logging::LoggingConfig;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args = Args::parse();
    
    // Initialize structured logging FIRST
    let logging_config = LoggingConfig::from_args(args.verbose, args.quiet);
    logging_config.init_structured_logging()?;
    
    tracing::info!("Gold Digger starting");
    
    // Rest of application...
}

Database Operations:

  • Add #[tracing::instrument] to database functions
  • Log connection establishment, query execution time
  • Include row count milestones (every 1000 rows)
  • Use log_database_url! macro for safe URL logging

CLI Integration:

  • Enhance --verbose to accept multiple occurrences (-v, -vv, -vvv)
  • Ensure --quiet overrides all verbosity settings
  • Add --log-format option for JSON/text output selection

✅ Acceptance Criteria

Core Functionality

  • Dependencies: Add tracing and tracing-subscriber with JSON support
  • Initialization: Logging system initializes before any operations
  • CLI Integration: --verbose count maps to log levels (warn→info→debug→trace)
  • Quiet Mode: --quiet suppresses all logs except errors
  • JSON Output: Structured JSON logs when verbose mode active

Security & Credentials

  • Zero Leakage: No DATABASE_URL, passwords, or credentials in any log
  • Redaction: Uses existing redact_url() for URL sanitization
  • Audit: All log output manually audited for credential exposure
  • Testing: Automated tests verify no credential leakage

Performance & Integration

  • Zero Cost: No logging overhead when disabled (quiet/non-verbose)
  • Database Logging: Connection, query execution, row processing milestones
  • Error Context: Enhanced error messages with structured context
  • Instrumentation: Key functions decorated with #[instrument]

Documentation & Testing

  • Usage Examples: CLI examples for different verbosity levels
  • Unit Tests: Logging configuration and initialization tests
  • Integration Tests: End-to-end logging behavior verification
  • Security Tests: Credential redaction verification tests

🧪 Validation Steps

Development Testing

# Test different verbosity levels
cargo run -- --help
cargo run -- -q --database-url "$DATABASE_URL" --query "SELECT 1"
cargo run -- -v --database-url "$DATABASE_URL" --query "SELECT * FROM users LIMIT 5" 
cargo run -- -vvv --database-url "$DATABASE_URL" --query "SELECT COUNT(*) FROM large_table"

Security Validation

# Verify no credential leakage in any verbosity mode
export DATABASE_URL="mysql://secret_user:secret_pass@host:3306/db"
cargo run -- -vvv --database-url "$DATABASE_URL" --query "SELECT 1" 2>&1 | grep -i "secret"
# Should return no matches

Performance Testing

# Ensure no overhead when logging disabled
hyperfine 'cargo run -- -q --database-url "$DATABASE_URL" --query "SELECT 1"'
hyperfine 'cargo run -- -vvv --database-url "$DATABASE_URL" --query "SELECT 1"'

🔗 Related Resources

🎯 Definition of Done

  • All Acceptance Criteria verified ✅
  • CI/CD pipeline passes on all platforms
  • Code review completed and approved
  • Documentation updated with logging usage examples
  • Security audit confirms zero credential exposure
  • Performance benchmarks show acceptable overhead
  • Integration tests demonstrate end-to-end functionality

Epic: #52 | Task: #11 | Requirements: 7.1-7.4 | Priority: High

Metadata

Metadata

Assignees

Labels

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions