# Logging Best Practices

Comprehensive guide for effective logging in production with the Custom PHP Framework.

## Overview

This document provides best practices for implementing, configuring, and maintaining the logging infrastructure in production environments.

## Choosing the Right Handler

### RotatingFileHandler vs Standard FileHandler

**Use RotatingFileHandler when**:
- Logs grow continuously and need automatic management
- Disk space constraints require automatic cleanup
- Historical log retention with automatic archival is needed
- Production environments requiring hands-off log management

**Use Standard FileHandler when**:
- External log rotation tools (logrotate) are already in place
- Logs are shipped to external systems immediately
- Development/testing environments with manual cleanup
- Very low-volume logging scenarios

### Factory Method Selection

```php
use App\Framework\Logging\Handlers\RotatingFileHandler;
use App\Framework\Core\ValueObjects\Byte;

// Production: INFO and above, daily rotation, 30 days retention
$handler = RotatingFileHandler::production('/var/www/html/storage/logs/app.log');

// Daily rotation: New log file every day at midnight
$handler = RotatingFileHandler::daily(
    logFile: '/var/www/html/storage/logs/app.log',
    maxFiles: 30,  // Keep 30 days of logs
    compress: true  // Compress rotated files (saves ~70% disk space)
);

// Weekly rotation: New log file every Monday
$handler = RotatingFileHandler::weekly(
    logFile: '/var/www/html/storage/logs/weekly.log',
    maxFiles: 12,  // Keep 3 months of weekly logs
    compress: true
);

// Size-based rotation: Rotate when file reaches size limit
$handler = RotatingFileHandler::withSizeRotation(
    logFile: '/var/www/html/storage/logs/api.log',
    maxFileSize: Byte::fromMegabytes(100),  // Rotate at 100MB
    maxFiles: 10,  // Keep 10 rotated files
    compress: true
);
```

## Rotation Strategy Selection

### Daily Rotation

**Best for**:
- Application logs with moderate volume (1-100 MB/day)
- Compliance requirements (daily log archival)
- Debugging workflows that align with daily releases/deployments
- General production application logging

**Configuration**:
```php
$handler = RotatingFileHandler::daily(
    logFile: '/var/www/html/storage/logs/app.log',
    maxFiles: 30,      // 30 days retention
    compress: true,    // Save disk space
    minLevel: LogLevel::INFO  // Production: INFO and above
);
```

**Retention Guidelines**:
- Development: 7 days
- Staging: 14 days
- Production: 30-90 days (compliance dependent)

### Weekly Rotation

**Best for**:
- Low-volume logs (<10 MB/day)
- Background job logs
- Scheduled task logs
- Non-critical system logs

**Configuration**:
```php
$handler = RotatingFileHandler::weekly(
    logFile: '/var/www/html/storage/logs/background.log',
    maxFiles: 12,      // 3 months retention
    compress: true
);
```

### Size-Based Rotation

**Best for**:
- High-volume API logs
- Variable traffic patterns (burst handling)
- Logs where size control is more important than time boundaries
- Debug logs during development

**Configuration**:
```php
// High-traffic API logs
$handler = RotatingFileHandler::withSizeRotation(
    logFile: '/var/www/html/storage/logs/api.log',
    maxFileSize: Byte::fromMegabytes(100),
    maxFiles: 20,  // 2GB total (20 × 100MB)
    compress: true
);

// Development: Smaller files for easier viewing
$handler = RotatingFileHandler::withSizeRotation(
    logFile: '/var/www/html/storage/logs/debug.log',
    maxFileSize: Byte::fromMegabytes(10),
    maxFiles: 5,
    compress: false  // No compression in dev for easier access
);
```

**Size Recommendations**:
- Development: 10-50 MB
- Staging: 50-100 MB
- Production: 100-500 MB (balance between rotation frequency and file count)

## Log Level Guidelines

### Production Log Levels

```php
use App\Framework\Logging\LogLevel;

// Production: INFO and above (default)
$handler = RotatingFileHandler::production($logFile);

// Custom production configuration
$handler = RotatingFileHandler::daily($logFile)
    ->withMinLevel(LogLevel::INFO);
```

**Level Selection**:
- **ERROR**: Critical failures requiring immediate attention
- **WARNING**: Potentially harmful situations that recovered
- **INFO**: Important business events (user registration, order completion)
- **DEBUG**: Detailed development information (disabled in production)

**Production Recommendations**:
- Main application log: INFO and above
- Security log: WARNING and above
- API access log: INFO (all requests)
- Background jobs: INFO (job start/completion)

### Development Log Levels

```php
// Development: All levels including DEBUG
$handler = RotatingFileHandler::daily(
    logFile: '/var/www/html/storage/logs/dev.log',
    maxFiles: 7,
    compress: false
)->withMinLevel(LogLevel::DEBUG);
```

### Separate Log Files by Severity

```php
// Error-only log for critical monitoring
$errorHandler = RotatingFileHandler::daily(
    logFile: '/var/www/html/storage/logs/errors.log',
    maxFiles: 90  // Keep errors longer
)->withMinLevel(LogLevel::ERROR);

// General application log
$appHandler = RotatingFileHandler::production(
    '/var/www/html/storage/logs/app.log'
);

// Attach both handlers to logger
$logger->addHandler($errorHandler);
$logger->addHandler($appHandler);
```

## Production Configuration Examples

### Standard Web Application

```php
// Application logs: Daily rotation, 30 days retention
$appHandler = RotatingFileHandler::production(
    '/var/www/html/storage/logs/app.log'
);

// Error logs: Keep longer for pattern analysis
$errorHandler = RotatingFileHandler::daily(
    logFile: '/var/www/html/storage/logs/errors.log',
    maxFiles: 90,
    compress: true
)->withMinLevel(LogLevel::ERROR);

// Security logs: Weekly rotation, compressed
$securityHandler = RotatingFileHandler::weekly(
    logFile: '/var/www/html/storage/logs/security.log',
    maxFiles: 52,  // 1 year
    compress: true
);
```

### High-Traffic API

```php
// API access logs: Size-based rotation for burst traffic
$apiHandler = RotatingFileHandler::withSizeRotation(
    logFile: '/var/www/html/storage/logs/api.log',
    maxFileSize: Byte::fromMegabytes(200),
    maxFiles: 20,  // 4GB total
    compress: true
)->withMinLevel(LogLevel::INFO);

// API errors: Separate file for monitoring
$apiErrorHandler = RotatingFileHandler::daily(
    logFile: '/var/www/html/storage/logs/api-errors.log',
    maxFiles: 60
)->withMinLevel(LogLevel::ERROR);
```

### Background Job Processing

```php
// Job logs: Daily rotation
$jobHandler = RotatingFileHandler::daily(
    logFile: '/var/www/html/storage/logs/jobs.log',
    maxFiles: 14,  // 2 weeks sufficient for job logs
    compress: true
)->withMinLevel(LogLevel::INFO);

// Failed job logs: Keep longer for debugging
$failedJobHandler = RotatingFileHandler::weekly(
    logFile: '/var/www/html/storage/logs/failed-jobs.log',
    maxFiles: 12,  // 3 months
    compress: true
)->withMinLevel(LogLevel::ERROR);
```

## Compression Best Practices

### When to Enable Compression

**Enable compression when**:
- Disk space is limited
- Log retention period is >7 days
- Logs are rarely accessed after rotation
- Production environments

**Disable compression when**:
- Development/debugging (frequent log access)
- Logs are shipped to external systems immediately
- Performance is critical (compression adds overhead)
- Very low log volume (<10 MB/day)

### Compression Trade-offs

```php
// Production: Compression enabled (recommended)
$handler = RotatingFileHandler::production($logFile);

// Development: Compression disabled for easier access
$handler = RotatingFileHandler::daily(
    logFile: $logFile,
    maxFiles: 7,
    compress: false  // No compression in dev
);
```

**Benefits**:
- Space savings: ~70% reduction on average
- Reduced backup costs
- Longer retention within disk limits

**Costs**:
- CPU overhead during rotation (negligible)
- Requires decompression to read old logs
- Slightly slower rotation process

## Health Monitoring

### LogHealthCheckCommand Usage

```bash
# Manual health check
docker exec php php console.php logs:health-check

# Detailed output with file information
docker exec php php console.php logs:health-check --detailed

# Auto-fix permission issues
docker exec php php console.php logs:health-check --fix-permissions
```

### Scheduled Health Checks

```php
use App\Framework\Scheduler\Services\SchedulerService;
use App\Framework\Scheduler\Schedules\CronSchedule;

// Daily health check at 2 AM
$scheduler->schedule(
    'log-health-check',
    CronSchedule::fromExpression('0 2 * * *'),
    function() {
        $command = new LogHealthCheckCommand();
        $input = new ConsoleInput(['logs:health-check'], new ConsoleOutput(), null);
        $exitCode = $command->execute($input);

        if ($exitCode !== ExitCode::SUCCESS) {
            // Alert operations team
            $this->alerting->sendAlert(
                level: AlertLevel::WARNING,
                message: 'Log health check failed'
            );
        }

        return ['exit_code' => $exitCode];
    }
);
```

### Health Check Metrics

Monitor these metrics from health checks:
- **Directory existence**: All required log directories present
- **Write permissions**: Can write to log directories
- **Disk space**: >100MB free (warning), >10% free (healthy)
- **Large files**: Individual files >50MB (rotation issue)
- **Total log size**: Track growth trends

### Automated Alerts

```php
// Alert on health check failures
final readonly class LogHealthMonitor
{
    public function checkAndAlert(): void
    {
        $health = $this->runHealthCheck();

        if (!$health['directories_ok']) {
            $this->alerting->sendAlert(
                level: AlertLevel::CRITICAL,
                message: 'Log directories missing or inaccessible',
                context: $health['directory_issues']
            );
        }

        if ($health['disk_space_low']) {
            $this->alerting->sendAlert(
                level: AlertLevel::WARNING,
                message: "Low disk space: {$health['free_space']}",
                context: $health['disk_info']
            );
        }

        if ($health['large_files_count'] > 0) {
            $this->alerting->sendAlert(
                level: AlertLevel::INFO,
                message: "{$health['large_files_count']} log files exceed 50MB",
                context: $health['large_files']
            );
        }
    }
}
```

## Docker/Container Deployment

### Directory Structure

```
storage/
└── logs/
    ├── app/            # Application logs
    ├── debug/          # Debug logs (dev only)
    ├── security/       # Security events
    └── jobs/           # Background job logs
```

### Docker Volume Configuration

```yaml
# docker-compose.yml
services:
  php:
    volumes:
      # Host mount for logs (accessible from host for monitoring)
      - ./storage/logs:/var/www/html/storage/logs
```

**Benefits of host mounts**:
- Logs persist across container restarts
- Direct access from host for monitoring tools
- Backup integration without entering container
- Log rotation tools on host can access files

### Permissions Setup

```bash
# Fix permissions for Docker container
chmod -R 777 storage/logs

# Or use Alpine container for one-time fix
docker run --rm -v $(pwd)/storage:/mnt alpine chmod -R 777 /mnt/logs
```

### Production Container Configuration

```dockerfile
# Dockerfile
FROM php:8.3-fpm

# Create log directories
RUN mkdir -p /var/www/html/storage/logs/app && \
    mkdir -p /var/www/html/storage/logs/security && \
    mkdir -p /var/www/html/storage/logs/jobs && \
    chown -R www-data:www-data /var/www/html/storage && \
    chmod -R 755 /var/www/html/storage/logs
```

## Performance Considerations

### Log Volume Management

**High-volume scenarios**:
```php
// Use size-based rotation for predictable disk usage
$handler = RotatingFileHandler::withSizeRotation(
    logFile: '/var/www/html/storage/logs/high-volume.log',
    maxFileSize: Byte::fromMegabytes(100),
    maxFiles: 20,
    compress: true
);

// Separate handlers for different log types
$errorHandler = RotatingFileHandler::daily($errorLog)
    ->withMinLevel(LogLevel::ERROR);  // Errors only

$debugHandler = RotatingFileHandler::withSizeRotation($debugLog, Byte::fromMegabytes(50))
    ->withMinLevel(LogLevel::DEBUG);  // Debug info
```

**Performance Benchmarks** (from integration tests):
- 1000 log entries: <5 seconds
- Rotation overhead: <100ms per rotation
- Compression overhead: ~200ms for 100MB file

### Memory Management

```php
// For very high-volume logging, consider async logging
use App\Framework\Queue\Queue;

final readonly class AsyncLoggingHandler implements LogHandler
{
    public function handle(LogRecord $record): void
    {
        // Queue log writes for background processing
        $job = new WriteLogJob($record);
        $this->queue->push(JobPayload::immediate($job));
    }
}
```

### Disk I/O Optimization

**Best practices**:
- Write logs synchronously for errors (data loss prevention)
- Buffer INFO/DEBUG logs for batch writes (performance)
- Use separate handlers for different log types (parallel writes)
- Monitor disk I/O metrics during rotation

## Security Considerations

### Log File Permissions

```bash
# Recommended permissions
chmod 755 storage/logs          # Directory: Read + execute for all, write for owner
chmod 644 storage/logs/*.log    # Files: Read for all, write for owner
```

**Security guidelines**:
- Never 777 permissions in production (security risk)
- Use 755 for directories (allows reading but prevents unauthorized writes)
- Use 644 for files (readable by monitoring tools, writable only by application)
- Separate user for web server and log access

### Sensitive Data Logging

**DO NOT log**:
- Passwords (plaintext or hashed)
- API keys and secrets
- Credit card numbers
- Personal identification numbers (SSN, etc.)
- Session tokens

**Safe logging patterns**:
```php
// ❌ Unsafe: Logs sensitive data
$logger->info('User login', [
    'password' => $password,  // NEVER log passwords
    'api_key' => $apiKey      // NEVER log keys
]);

// ✅ Safe: Logs only necessary information
$logger->info('User login', [
    'user_id' => $userId,
    'ip_address' => $ipAddress,
    'user_agent' => $userAgent
]);

// ✅ Safe: Mask sensitive data
$logger->info('Payment processed', [
    'card_last_four' => substr($cardNumber, -4),  // Only last 4 digits
    'amount' => $amount,
    'transaction_id' => $transactionId
]);
```

### Security Event Logging

```php
// Use framework's OWASP security logger for security events
use App\Framework\Security\OWASPSecurityLogger;
use App\Framework\Security\OWASPEventIdentifier;

$this->owaspLogger->logSecurityEvent(
    new SecurityEventType(OWASPEventIdentifier::AUTHN_LOGIN_FAILURE),
    request: $request,
    context: [
        'username' => $username,
        'ip_address' => $request->server->getRemoteAddr(),
        'failure_reason' => 'Invalid credentials'
    ]
);
```

## Troubleshooting

### Common Issues

#### Issue: Logs not rotating

**Symptoms**:
- Log file grows continuously
- No `.1`, `.2` rotation files created

**Diagnosis**:
```bash
# Check file permissions
ls -la storage/logs/

# Check disk space
df -h

# Verify handler configuration
docker exec php php console.php logs:health-check --detailed
```

**Solutions**:
```php
// Verify rotation configuration
$handler = RotatingFileHandler::daily($logFile, maxFiles: 30);

// Check if logs are actually being written
if (!file_exists($logFile)) {
    // Permission issue or incorrect path
}

// Manually trigger rotation for testing
touch($logFile, strtotime('yesterday'));
$handler->handle($logRecord);  // Should rotate now
```

#### Issue: Permission denied errors

**Symptoms**:
- Cannot write to log files
- Health check reports permission errors

**Solutions**:
```bash
# Fix permissions (development)
chmod -R 777 storage/logs

# Fix permissions (production - more secure)
chown -R www-data:www-data storage/logs
chmod -R 755 storage/logs
chmod -R 644 storage/logs/*.log

# Use health check auto-fix
docker exec php php console.php logs:health-check --fix-permissions
```

#### Issue: Disk space full

**Symptoms**:
- Health check reports low disk space
- Log rotation fails

**Solutions**:
```bash
# Check disk usage
du -sh storage/logs/*

# Find largest log files
find storage/logs -type f -exec ls -lh {} \; | sort -k5 -rh | head -10

# Manually clean old logs
find storage/logs -name "*.log.*" -mtime +30 -delete

# Increase compression for existing logs
find storage/logs -name "*.log.[0-9]*" ! -name "*.gz" -exec gzip {} \;
```

**Prevention**:
```php
// Reduce retention period
$handler = RotatingFileHandler::daily($logFile, maxFiles: 14);  // 14 days instead of 30

// Reduce file size for size-based rotation
$handler = RotatingFileHandler::withSizeRotation(
    $logFile,
    maxFileSize: Byte::fromMegabytes(50),  // 50MB instead of 100MB
    maxFiles: 10
);

// Enable compression if not already
$handler = RotatingFileHandler::daily($logFile, compress: true);
```

#### Issue: Performance degradation

**Symptoms**:
- Slow request processing
- High disk I/O during logging

**Solutions**:
```php
// Separate handlers by log type to parallelize writes
$errorHandler = RotatingFileHandler::daily('/var/www/html/storage/logs/errors.log')
    ->withMinLevel(LogLevel::ERROR);

$infoHandler = RotatingFileHandler::daily('/var/www/html/storage/logs/info.log')
    ->withMinLevel(LogLevel::INFO)
    ->withMaxLevel(LogLevel::WARNING);

// Consider async logging for high-volume scenarios
use App\Framework\Logging\Handlers\QueuedLogHandler;

$asyncHandler = new QueuedLogHandler($queue, $handler);
```

## Integration with Framework Systems

### Scheduler Integration

```php
// Automated log rotation cleanup
$scheduler->schedule(
    'log-cleanup',
    CronSchedule::fromExpression('0 3 * * *'),  // Daily at 3 AM
    function() {
        // Remove logs older than retention policy
        $this->logCleanupService->cleanupExpiredLogs();

        return ['cleaned' => true];
    }
);

// Health monitoring
$scheduler->schedule(
    'log-health-check',
    IntervalSchedule::every(Duration::fromHours(6)),
    function() {
        $command = new LogHealthCheckCommand();
        $input = new ConsoleInput(['logs:health-check'], new ConsoleOutput(), null);

        return ['exit_code' => $command->execute($input)];
    }
);
```

### Queue Integration

```php
// Background log processing for high-volume scenarios
final class ProcessLogBatchJob
{
    public function handle(): void
    {
        $logBatch = $this->logBuffer->flush();

        foreach ($logBatch as $logRecord) {
            $this->handler->handle($logRecord);
        }
    }
}
```

### Event System Integration

```php
// Log important domain events
use App\Framework\Event\EventHandler;

#[EventHandler]
final readonly class UserRegistrationLogger
{
    public function handle(UserRegisteredEvent $event): void
    {
        $this->logger->info('User registered', [
            'user_id' => $event->userId,
            'email' => $event->email->getMasked(),
            'registration_method' => $event->method
        ]);
    }
}
```

## Monitoring and Alerting

### Metrics to Track

1. **Log Volume Metrics**:
   - Logs per hour/day
   - Growth rate trends
   - Rotation frequency

2. **Performance Metrics**:
   - Write latency (should be <10ms)
   - Rotation duration (should be <1s)
   - Disk I/O utilization

3. **Health Metrics**:
   - Disk space free percentage
   - Number of files exceeding size thresholds
   - Permission check failures

4. **Error Metrics**:
   - Error log volume (sudden spikes indicate issues)
   - Failed rotation attempts
   - Write permission errors

### Alert Configuration

```php
// Example monitoring integration
final readonly class LogMonitoringService
{
    public function collectMetrics(): array
    {
        return [
            'total_log_size' => $this->getTotalLogSize(),
            'log_file_count' => $this->getLogFileCount(),
            'largest_file_size' => $this->getLargestFileSize(),
            'disk_space_free' => $this->getDiskSpaceFree(),
            'rotation_count_24h' => $this->getRotationCount(Duration::fromHours(24))
        ];
    }

    public function checkThresholds(array $metrics): array
    {
        $alerts = [];

        if ($metrics['disk_space_free'] < 1_000_000_000) {  // <1GB
            $alerts[] = [
                'level' => 'critical',
                'message' => 'Log disk space critically low'
            ];
        }

        if ($metrics['largest_file_size'] > 500_000_000) {  // >500MB
            $alerts[] = [
                'level' => 'warning',
                'message' => 'Large log file detected (rotation issue?)'
            ];
        }

        return $alerts;
    }
}
```

## Summary Checklist

### Production Deployment

- [ ] Configure appropriate rotation strategy (daily/weekly/size-based)
- [ ] Set retention period based on compliance requirements
- [ ] Enable compression for rotated files
- [ ] Set production log level (INFO and above)
- [ ] Configure separate log files by severity (errors, security, etc.)
- [ ] Set up Docker volume mounts for log persistence
- [ ] Fix file permissions (755 directories, 644 files)
- [ ] Schedule health checks (daily recommended)
- [ ] Configure monitoring and alerting
- [ ] Test log rotation under load
- [ ] Document log access procedures for operations team

### Development Setup

- [ ] Use DEBUG log level for development
- [ ] Disable compression for easier access
- [ ] Use shorter retention (7 days sufficient)
- [ ] Smaller file size limits for size-based rotation
- [ ] Regular cleanup to prevent disk space issues
- [ ] Test rotation locally before deploying

### Ongoing Maintenance

- [ ] Monitor disk space weekly
- [ ] Review health check results daily
- [ ] Analyze log volume trends monthly
- [ ] Clean up old logs exceeding retention period
- [ ] Review and update alerting thresholds quarterly
- [ ] Test disaster recovery procedures (log restoration)
- [ ] Update documentation as logging patterns evolve

## Additional Resources

- **LogHealthCheckCommand**: `docs/logging/log-health-check-command.md`
- **RotatingFileHandler Implementation**: `src/Framework/Logging/Handlers/RotatingFileHandler.php`
- **Integration Tests**: `tests/Integration/Framework/Logging/LoggingInfrastructureTest.php`
- **OWASP Security Logging**: `docs/claude/security-patterns.md`
