
## 3. **includes/logger.php** (Logging Class)

```php
<?php
/**
 * Logger Class
 * Handles all system logging
 */

class Logger {
    private $logDir;
    private $logLevel;
    
    const LEVEL_DEBUG = 0;
    const LEVEL_INFO = 1;
    const LEVEL_WARNING = 2;
    const LEVEL_ERROR = 3;
    const LEVEL_CRITICAL = 4;
    
    private static $levelNames = [
        self::LEVEL_DEBUG => 'DEBUG',
        self::LEVEL_INFO => 'INFO',
        self::LEVEL_WARNING => 'WARNING',
        self::LEVEL_ERROR => 'ERROR',
        self::LEVEL_CRITICAL => 'CRITICAL'
    ];
    
    public function __construct($logDir = null, $logLevel = self::LEVEL_INFO) {
        $this->logDir = $logDir ?: __DIR__ . '/../logs/';
        $this->logLevel = $logLevel;
        
        if (!is_dir($this->logDir)) {
            mkdir($this->logDir, 0755, true);
        }
    }
    
    /**
     * Log a message
     */
    public function log($level, $message, $context = [], $file = 'errors.log') {
        if ($level < $this->logLevel) {
            return;
        }
        
        $timestamp = date('Y-m-d H:i:s');
        $levelName = self::$levelNames[$level] ?? 'UNKNOWN';
        $logFile = $this->logDir . $file;
        
        $logMessage = "[$timestamp] [$levelName] ";
        
        if (!empty($context)) {
            $logMessage .= json_encode($context) . ' - ';
        }
        
        $logMessage .= $message . "\n";
        
        file_put_contents($logFile, $logMessage, FILE_APPEND);
        
        // Rotate log if too large (10MB)
        if (file_exists($logFile) && filesize($logFile) > 10 * 1024 * 1024) {
            $this->rotateLog($file);
        }
    }
    
    /**
     * Log debug message
     */
    public function debug($message, $context = [], $file = 'errors.log') {
        $this->log(self::LEVEL_DEBUG, $message, $context, $file);
    }
    
    /**
     * Log info message
     */
    public function info($message, $context = [], $file = 'errors.log') {
        $this->log(self::LEVEL_INFO, $message, $context, $file);
    }
    
    /**
     * Log warning message
     */
    public function warning($message, $context = [], $file = 'errors.log') {
        $this->log(self::LEVEL_WARNING, $message, $context, $file);
    }
    
    /**
     * Log error message
     */
    public function error($message, $context = [], $file = 'errors.log') {
        $this->log(self::LEVEL_ERROR, $message, $context, $file);
    }
    
    /**
     * Log critical message
     */
    public function critical($message, $context = [], $file = 'errors.log') {
        $this->log(self::LEVEL_CRITICAL, $message, $context, $file);
    }
    
    /**
     * Log access (login/logout, page views)
     */
    public function access($userId, $action, $details = null) {
        $context = [
            'user_id' => $userId,
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            'action' => $action,
            'details' => $details
        ];
        $this->info($action, $context, 'access.log');
    }
    
    /**
     * Log AI API calls
     */
    public function ai($action, $success, $duration = null, $error = null) {
        $context = [
            'action' => $action,
            'success' => $success,
            'duration' => $duration,
            'error' => $error
        ];
        $level = $success ? self::LEVEL_INFO : self::LEVEL_ERROR;
        $this->log($level, "AI $action", $context, 'ai.log');
    }
    
    /**
     * Log cron job execution
     */
    public function cron($jobName, $status, $details = null) {
        $context = [
            'job' => $jobName,
            'status' => $status,
            'details' => $details
        ];
        $this->info("Cron job: $jobName", $context, 'cron.log');
    }
    
    /**
     * Rotate log file
     */
    private function rotateLog($file) {
        $logFile = $this->logDir . $file;
        $backupFile = $this->logDir . $file . '.' . date('Y-m-d-His') . '.bak';
        
        rename($logFile, $backupFile);
        
        // Compress old log
        if (function_exists('gzopen')) {
            $gzFile = $backupFile . '.gz';
            $gz = gzopen($gzFile, 'w9');
            gzwrite($gz, file_get_contents($backupFile));
            gzclose($gz);
            unlink($backupFile);
        }
        
        // Delete logs older than 30 days
        $oldLogs = glob($this->logDir . $file . '.*.bak*');
        foreach ($oldLogs as $oldLog) {
            if (filemtime($oldLog) < time() - 30 * 86400) {
                unlink($oldLog);
            }
        }
    }
    
    /**
     * Get log file content
     */
    public function getLogs($file, $lines = 100) {
        $logFile = $this->logDir . $file;
        
        if (!file_exists($logFile)) {
            return [];
        }
        
        $logs = [];
        $handle = fopen($logFile, 'r');
        
        if ($handle) {
            // Get last N lines
            $buffer = [];
            while (($line = fgets($handle)) !== false) {
                $buffer[] = $line;
                if (count($buffer) > $lines) {
                    array_shift($buffer);
                }
            }
            fclose($handle);
            
            foreach ($buffer as $line) {
                if (preg_match('/\[(.*?)\] \[(.*?)\] (.*)/', $line, $matches)) {
                    $logs[] = [
                        'timestamp' => $matches[1],
                        'level' => $matches[2],
                        'message' => trim($matches[3])
                    ];
                }
            }
        }
        
        return array_reverse($logs);
    }
    
    /**
     * Clear log file
     */
    public function clearLog($file) {
        $logFile = $this->logDir . $file;
        if (file_exists($logFile)) {
            file_put_contents($logFile, '');
            return true;
        }
        return false;
    }
    
    /**
     * Get log file size
     */
    public function getLogSize($file) {
        $logFile = $this->logDir . $file;
        if (file_exists($logFile)) {
            return filesize($logFile);
        }
        return 0;
    }
    
    /**
     * Get log statistics
     */
    public function getStats() {
        $stats = [];
        $logFiles = ['errors.log', 'access.log', 'ai.log', 'cron.log'];
        
        foreach ($logFiles as $file) {
            $logFile = $this->logDir . $file;
            $stats[$file] = [
                'exists' => file_exists($logFile),
                'size' => file_exists($logFile) ? filesize($logFile) : 0,
                'modified' => file_exists($logFile) ? filemtime($logFile) : null
            ];
        }
        
        return $stats;
    }
}

// Global logger instance
$logger = null;

function getLogger() {
    global $logger;
    if ($logger === null) {
        $logger = new Logger();
    }
    return $logger;
}

// Error handler to log PHP errors
function logErrorHandler($errno, $errstr, $errfile, $errline) {
    $logger = getLogger();
    $context = [
        'file' => $errfile,
        'line' => $errline,
        'errno' => $errno
    ];
    $logger->error($errstr, $context);
    return false;
}

// Exception handler
function logExceptionHandler($exception) {
    $logger = getLogger();
    $context = [
        'file' => $exception->getFile(),
        'line' => $exception->getLine(),
        'trace' => $exception->getTraceAsString()
    ];
    $logger->critical($exception->getMessage(), $context);
}

// Register handlers
set_error_handler('logErrorHandler');
set_exception_handler('logExceptionHandler');