'DEBUG', self::LEVEL_INFO => 'INFO', self::LEVEL_WARNING => 'WARNING', self::LEVEL_ERROR => 'ERROR', self::LEVEL_CRITICAL => 'CRITICAL' ); /** * Log settings */ private $settings = array(); /** * Get instance */ public static function instance() { if (is_null(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ private function __construct() { $this->init(); } /** * Initialize logger */ private function init() { $this->settings = array( 'enabled' => get_option('backup_logging_enabled', true), 'level' => get_option('backup_logging_level', self::LEVEL_INFO), 'file_enabled' => get_option('backup_logging_file_enabled', true), 'database_enabled' => false, // Disabled to avoid complex database setup 'email_enabled' => get_option('backup_logging_email_enabled', false), 'wordpress_debug_enabled' => get_option('backup_logging_wp_debug_enabled', true), // Use WordPress debug instead 'log_file' => WP_CONTENT_DIR . '/tigerstyle-backup-logs/backup.log', 'max_file_size' => 10485760, // 10MB 'max_log_files' => 5, 'email_level' => self::LEVEL_ERROR, 'email_recipient' => get_option('admin_email') ); // Ensure log directory exists $log_dir = dirname($this->settings['log_file']); if (!is_dir($log_dir)) { wp_mkdir_p($log_dir); // Protect log directory $htaccess_content = "Order deny,allow\nDeny from all\n"; file_put_contents($log_dir . '/.htaccess', $htaccess_content); } } /** * Log debug message */ public function debug($message, $context = array()) { $this->log(self::LEVEL_DEBUG, $message, $context); } /** * Log info message */ public function info($message, $context = array()) { $this->log(self::LEVEL_INFO, $message, $context); } /** * Log warning message */ public function warning($message, $context = array()) { $this->log(self::LEVEL_WARNING, $message, $context); } /** * Log error message */ public function error($message, $context = array()) { $this->log(self::LEVEL_ERROR, $message, $context); } /** * Log critical message */ public function critical($message, $context = array()) { $this->log(self::LEVEL_CRITICAL, $message, $context); } /** * Main logging method */ private function log($level, $message, $context = array()) { if (!$this->settings['enabled'] || $level < $this->settings['level']) { return; } $log_entry = $this->create_log_entry($level, $message, $context); // Log to file if ($this->settings['file_enabled']) { $this->log_to_file($log_entry); } // Log to database if ($this->settings['database_enabled']) { $this->log_to_database($level, $message, $context); } // Log to WordPress debug if ($this->settings['wordpress_debug_enabled'] && WP_DEBUG_LOG) { $this->log_to_wordpress_debug($log_entry); } // Send email for critical errors if ($this->settings['email_enabled'] && $level >= $this->settings['email_level']) { $this->send_email_notification($level, $message, $context); } } /** * Create formatted log entry */ private function create_log_entry($level, $message, $context) { $timestamp = current_time('Y-m-d H:i:s'); $level_name = $this->level_names[$level]; $user_info = $this->get_user_info(); $memory_usage = $this->format_bytes(memory_get_usage(true)); $log_data = array( 'timestamp' => $timestamp, 'level' => $level_name, 'message' => $message, 'context' => $context, 'user' => $user_info, 'memory' => $memory_usage, 'request_id' => $this->get_request_id() ); return $log_data; } /** * Log to file */ private function log_to_file($log_entry) { // Check if log rotation is needed if (file_exists($this->settings['log_file']) && filesize($this->settings['log_file']) > $this->settings['max_file_size']) { $this->rotate_log_file(); } $formatted_entry = $this->format_log_entry_for_file($log_entry); // Append to log file file_put_contents($this->settings['log_file'], $formatted_entry . "\n", FILE_APPEND | LOCK_EX); } /** * Log to database */ private function log_to_database($level, $message, $context) { global $wpdb; $table_name = $wpdb->prefix . 'tigerstyle_backup_logs'; $wpdb->insert( $table_name, array( 'created_at' => current_time('mysql'), 'level' => $this->level_names[$level], 'message' => $message, 'context' => json_encode($context), 'user_id' => get_current_user_id(), 'user_ip' => $this->get_user_ip(), 'memory_usage' => memory_get_usage(true), 'request_id' => $this->get_request_id() ), array('%s', '%s', '%s', '%s', '%d', '%s', '%d', '%s') ); } /** * Log to WordPress debug */ private function log_to_wordpress_debug($log_entry) { $formatted_entry = sprintf( '[TigerStyle Backup] [%s] %s %s', $log_entry['level'], $log_entry['message'], !empty($log_entry['context']) ? json_encode($log_entry['context']) : '' ); error_log($formatted_entry); } /** * Send email notification */ private function send_email_notification($level, $message, $context) { if (!$this->settings['email_recipient']) { return; } $subject = sprintf( '[%s] TigerStyle SEO Backup %s: %s', get_bloginfo('name'), $this->level_names[$level], $message ); $body = "A backup system event occurred:\n\n"; $body .= "Level: " . $this->level_names[$level] . "\n"; $body .= "Message: " . $message . "\n"; $body .= "Time: " . current_time('Y-m-d H:i:s') . "\n"; $body .= "Site: " . site_url() . "\n"; if (!empty($context)) { $body .= "\nContext:\n" . print_r($context, true); } $body .= "\n---\nThis is an automated message from TigerStyle SEO Backup System."; wp_mail($this->settings['email_recipient'], $subject, $body); } /** * Format log entry for file output */ private function format_log_entry_for_file($log_entry) { $context_str = !empty($log_entry['context']) ? json_encode($log_entry['context']) : ''; return sprintf( '[%s] [%s] [%s] [MEM:%s] [REQ:%s] %s %s', $log_entry['timestamp'], $log_entry['level'], $log_entry['user']['display'], $log_entry['memory'], $log_entry['request_id'], $log_entry['message'], $context_str ); } /** * Rotate log file */ private function rotate_log_file() { $base_file = $this->settings['log_file']; // Remove oldest log file $oldest_log = $base_file . '.' . $this->settings['max_log_files']; if (file_exists($oldest_log)) { unlink($oldest_log); } // Rotate existing log files for ($i = $this->settings['max_log_files'] - 1; $i >= 1; $i--) { $current_log = $base_file . '.' . $i; $next_log = $base_file . '.' . ($i + 1); if (file_exists($current_log)) { rename($current_log, $next_log); } } // Move current log to .1 if (file_exists($base_file)) { rename($base_file, $base_file . '.1'); } } /** * Get user information */ private function get_user_info() { $user = wp_get_current_user(); if ($user->ID) { return array( 'id' => $user->ID, 'login' => $user->user_login, 'display' => $user->display_name, 'email' => $user->user_email ); } else { return array( 'id' => 0, 'login' => 'guest', 'display' => 'Guest User', 'email' => '' ); } } /** * Get user IP address */ private function get_user_ip() { if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { return sanitize_text_field($_SERVER['HTTP_X_FORWARDED_FOR']); } elseif (!empty($_SERVER['HTTP_X_REAL_IP'])) { return sanitize_text_field($_SERVER['HTTP_X_REAL_IP']); } elseif (!empty($_SERVER['REMOTE_ADDR'])) { return sanitize_text_field($_SERVER['REMOTE_ADDR']); } return 'unknown'; } /** * Get request ID for tracking related log entries */ private function get_request_id() { static $request_id = null; if ($request_id === null) { $request_id = substr(md5(uniqid(mt_rand(), true)), 0, 8); } return $request_id; } /** * Format bytes for display */ private function format_bytes($bytes, $precision = 2) { $units = array('B', 'KB', 'MB', 'GB', 'TB'); for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) { $bytes /= 1024; } return round($bytes, $precision) . $units[$i]; } /** * Get recent log entries */ public function get_recent_logs($limit = 100, $level_filter = null) { global $wpdb; $table_name = $wpdb->prefix . 'tigerstyle_backup_logs'; $sql = "SELECT * FROM {$table_name}"; $where_conditions = array(); $where_values = array(); if ($level_filter && isset($this->level_names[$level_filter])) { $where_conditions[] = "level = %s"; $where_values[] = $this->level_names[$level_filter]; } if (!empty($where_conditions)) { $sql .= " WHERE " . implode(' AND ', $where_conditions); } $sql .= " ORDER BY created_at DESC LIMIT %d"; $where_values[] = $limit; if (!empty($where_values)) { $sql = $wpdb->prepare($sql, $where_values); } return $wpdb->get_results($sql, ARRAY_A); } /** * Export logs to file */ public function export_logs($format = 'json', $date_from = null, $date_to = null) { global $wpdb; $table_name = $wpdb->prefix . 'tigerstyle_backup_logs'; $sql = "SELECT * FROM {$table_name}"; $where_conditions = array(); $where_values = array(); if ($date_from) { $where_conditions[] = "created_at >= %s"; $where_values[] = $date_from; } if ($date_to) { $where_conditions[] = "created_at <= %s"; $where_values[] = $date_to; } if (!empty($where_conditions)) { $sql .= " WHERE " . implode(' AND ', $where_conditions); } $sql .= " ORDER BY created_at DESC"; if (!empty($where_values)) { $sql = $wpdb->prepare($sql, $where_values); } $logs = $wpdb->get_results($sql, ARRAY_A); switch ($format) { case 'json': return json_encode($logs, JSON_PRETTY_PRINT); case 'csv': return $this->logs_to_csv($logs); case 'txt': return $this->logs_to_text($logs); default: return $logs; } } /** * Convert logs to CSV format */ private function logs_to_csv($logs) { if (empty($logs)) { return ''; } $csv = "Timestamp,Level,Message,User ID,User IP,Memory Usage,Request ID\n"; foreach ($logs as $log) { $csv .= sprintf( '"%s","%s","%s","%s","%s","%s","%s"' . "\n", $log['created_at'], $log['level'], str_replace('"', '""', $log['message']), $log['user_id'], $log['user_ip'], $log['memory_usage'], $log['request_id'] ); } return $csv; } /** * Convert logs to text format */ private function logs_to_text($logs) { if (empty($logs)) { return ''; } $text = "TigerStyle SEO Backup Logs Export\n"; $text .= "Generated: " . current_time('Y-m-d H:i:s') . "\n"; $text .= str_repeat('=', 50) . "\n\n"; foreach ($logs as $log) { $text .= sprintf( "[%s] [%s] %s\n", $log['created_at'], $log['level'], $log['message'] ); if (!empty($log['context'])) { $context = json_decode($log['context'], true); if ($context) { $text .= " Context: " . print_r($context, true) . "\n"; } } $text .= "\n"; } return $text; } /** * Clear old logs */ public function cleanup_old_logs($days = 30) { global $wpdb; $table_name = $wpdb->prefix . 'tigerstyle_backup_logs'; $cutoff_date = date('Y-m-d H:i:s', strtotime("-{$days} days")); $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM {$table_name} WHERE created_at < %s", $cutoff_date ) ); $this->info("Cleaned up old log entries", array( 'deleted_count' => $deleted, 'cutoff_date' => $cutoff_date )); return $deleted; } /** * Get log statistics */ public function get_log_statistics($days = 7) { global $wpdb; $table_name = $wpdb->prefix . 'tigerstyle_backup_logs'; $cutoff_date = date('Y-m-d H:i:s', strtotime("-{$days} days")); $stats = array(); // Total logs $stats['total'] = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE created_at >= %s", $cutoff_date ) ); // Logs by level $level_stats = $wpdb->get_results( $wpdb->prepare( "SELECT level, COUNT(*) as count FROM {$table_name} WHERE created_at >= %s GROUP BY level", $cutoff_date ), ARRAY_A ); $stats['by_level'] = array(); foreach ($level_stats as $level_stat) { $stats['by_level'][$level_stat['level']] = $level_stat['count']; } // Recent errors $stats['recent_errors'] = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE level IN ('ERROR', 'CRITICAL') AND created_at >= %s ORDER BY created_at DESC LIMIT 10", $cutoff_date ), ARRAY_A ); return $stats; } }