AlkantarClanX12

Your IP : 216.73.217.24


Current Path : /www/capitalgmcbuickregina_830/public/wp-content/plugins/leadbox/lib/
Upload File :
Current File : /www/capitalgmcbuickregina_830/public/wp-content/plugins/leadbox/lib/class-logger.php

<?php
/**
 * Leadbox Logger
 *
 * PSR-3 compliant logging with structured context
 *
 * @package Leadbox
 * @since 6.5.0
 */

use Psr\Log\AbstractLogger;
use Psr\Log\LogLevel;

/**
 * Leadbox Logger Class
 *
 * Provides structured logging with automatic context injection
 */
class LB_Logger extends AbstractLogger
{
	/**
	 * Minimum log level to record
	 *
	 * @var string
	 */
	private $min_level;

	/**
	 * Log level hierarchy
	 *
	 * @var array
	 */
	private static $levels = array(
		LogLevel::DEBUG => 100,
		LogLevel::INFO => 200,
		LogLevel::NOTICE => 250,
		LogLevel::WARNING => 300,
		LogLevel::ERROR => 400,
		LogLevel::CRITICAL => 500,
		LogLevel::ALERT => 550,
		LogLevel::EMERGENCY => 600,
	);

	/**
	 * Singleton instance
	 *
	 * @var LB_Logger
	 */
	private static $instance = null;

	/**
	 * Request ID for this request
	 *
	 * @var string
	 */
	private $request_id;

	/**
	 * Private constructor (singleton pattern)
	 */
	private function __construct()
	{
		// Set minimum log level from wp-config or default to ERROR (production-safe)
		$this->min_level = defined('LEADBOX_LOG_LEVEL')
			? LEADBOX_LOG_LEVEL
			: LogLevel::ERROR;

		// Generate request ID
		$this->request_id = $this->generate_request_id();
	}

	/**
	 * Get singleton instance
	 *
	 * @return LB_Logger
	 */
	public static function getInstance()
	{
		if (self::$instance === null) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Log a message
	 *
	 * @param string $level Log level
	 * @param string $message Log message
	 * @param array $context Additional context
	 */
	public function log($level, $message, array $context = array())
	{
		// Check if this level should be logged
		if (!$this->should_log($level)) {
			return;
		}

		// Build log entry
		$entry = $this->build_log_entry($level, $message, $context);

		// Write to file (only if WP_DEBUG_LOG enabled)
		$this->write_to_file($entry);

		// Database logging disabled by default (opt-in only)
		if (defined('LEADBOX_LOG_TO_DATABASE') && LEADBOX_LOG_TO_DATABASE) {
			$this->write_to_database($entry);
		}

		// Allow external monitoring services
		do_action('leadbox_log_entry', $entry);
	}

	/**
	 * Check if log level should be recorded
	 *
	 * @param string $level Log level
	 * @return bool
	 */
	private function should_log($level)
	{
		$level_value = self::$levels[$level] ?? 0;
		$min_value = self::$levels[$this->min_level] ?? 0;

		return $level_value >= $min_value;
	}

	/**
	 * Build structured log entry
	 *
	 * @param string $level Log level
	 * @param string $message Log message
	 * @param array $context Additional context
	 * @return array
	 */
	private function build_log_entry($level, $message, array $context)
	{
		// Interpolate context variables into message
		$message = $this->interpolate($message, $context);

		// Build entry
		$entry = array(
			'timestamp' => current_time('mysql'),
			'timestamp_unix' => time(),
			'level' => strtoupper($level),
			'message' => $message,
			'request_id' => $this->request_id,
			'context' => $context,
		);

		// Add automatic context
		$entry['user_id'] = get_current_user_id();
		$entry['ip_address'] = $this->get_ip_address();
		$entry['url'] = $this->get_current_url();
		$entry['user_agent'] = isset($_SERVER['HTTP_USER_AGENT'])
			? sanitize_text_field($_SERVER['HTTP_USER_AGENT'])
			: null;

		// Add memory and performance data for errors
		if (in_array($level, array(LogLevel::ERROR, LogLevel::CRITICAL, LogLevel::EMERGENCY))) {
			$entry['memory_usage'] = memory_get_usage(true);
			$entry['memory_peak'] = memory_get_peak_usage(true);
		}

		return $entry;
	}

	/**
	 * Interpolate context values into message
	 *
	 * @param string $message Message with placeholders
	 * @param array $context Context values
	 * @return string
	 */
	private function interpolate($message, array $context)
	{
		$replace = array();

		foreach ($context as $key => $val) {
			if (is_scalar($val) || (is_object($val) && method_exists($val, '__toString'))) {
				$replace['{' . $key . '}'] = $val;
			}
		}

		return strtr($message, $replace);
	}

	/**
	 * Write log entry to file
	 *
	 * @param array $entry Log entry
	 */
	private function write_to_file(array $entry)
	{
		// Use WordPress debug log if enabled
		if (!defined('WP_DEBUG_LOG') || !WP_DEBUG_LOG) {
			return;
		}

		$log_line = sprintf(
			"[%s] %s: %s (Request: %s, User: %d)\n",
			$entry['timestamp'],
			$entry['level'],
			$entry['message'],
			$entry['request_id'],
			$entry['user_id']
		);

		// Add context if present
		if (!empty($entry['context'])) {
			$log_line .= 'Context: ' . wp_json_encode($entry['context']) . "\n";
		}

		// Write to separate Leadbox log file
		$log_file = WP_CONTENT_DIR . '/leadbox-debug.log';

		// Append to file (creates file if doesn't exist)
		file_put_contents($log_file, $log_line, FILE_APPEND | LOCK_EX);
	}

	/**
	 * Write log entry to database
	 *
	 * @param array $entry Log entry
	 */
	private function write_to_database(array $entry)
	{
		global $wpdb;

		// Only log errors and above to database
		$level_value = self::$levels[$entry['level']] ?? 0;
		if ($level_value < self::$levels[LogLevel::ERROR]) {
			return;
		}

		// Table name
		$table = $wpdb->prefix . 'leadbox_logs';

		// Check if table exists (create on first use)
		if ($wpdb->get_var("SHOW TABLES LIKE '$table'") !== $table) {
			$this->create_log_table();
		}

		// Insert log entry
		$wpdb->insert(
			$table,
			array(
				'timestamp' => $entry['timestamp'],
				'level' => $entry['level'],
				'message' => $entry['message'],
				'request_id' => $entry['request_id'],
				'user_id' => $entry['user_id'],
				'ip_address' => $entry['ip_address'],
				'url' => $entry['url'],
				'context' => wp_json_encode($entry['context']),
				'memory_usage' => $entry['memory_usage'] ?? null,
			),
			array('%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s', '%d')
		);
	}

	/**
	 * Create log table
	 */
	private function create_log_table()
	{
		global $wpdb;

		$table = $wpdb->prefix . 'leadbox_logs';
		$charset_collate = $wpdb->get_charset_collate();

		$sql = "CREATE TABLE $table (
			id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
			timestamp datetime NOT NULL,
			level varchar(20) NOT NULL,
			message text NOT NULL,
			request_id varchar(40) NOT NULL,
			user_id bigint(20) unsigned DEFAULT NULL,
			ip_address varchar(45) DEFAULT NULL,
			url text DEFAULT NULL,
			context longtext DEFAULT NULL,
			memory_usage bigint(20) unsigned DEFAULT NULL,
			PRIMARY KEY (id),
			KEY level (level),
			KEY timestamp (timestamp),
			KEY request_id (request_id),
			KEY user_id (user_id)
		) $charset_collate;";

		require_once ABSPATH . 'wp-admin/includes/upgrade.php';
		dbDelta($sql);
	}

	/**
	 * Generate unique request ID
	 *
	 * @return string
	 */
	private function generate_request_id()
	{
		return substr(md5(uniqid('', true)), 0, 16);
	}

	/**
	 * Get client IP address
	 *
	 * @return string|null
	 */
	private function get_ip_address()
	{
		$headers = array(
			'HTTP_CF_CONNECTING_IP',
			'HTTP_X_FORWARDED_FOR',
			'HTTP_X_REAL_IP',
			'REMOTE_ADDR',
		);

		foreach ($headers as $header) {
			if (!empty($_SERVER[$header])) {
				$ip = sanitize_text_field($_SERVER[$header]);
				// Take first IP if multiple
				if (strpos($ip, ',') !== false) {
					$ip = trim(explode(',', $ip)[0]);
				}
				return $ip;
			}
		}

		return null;
	}

	/**
	 * Get current URL
	 *
	 * @return string|null
	 */
	private function get_current_url()
	{
		if (!isset($_SERVER['REQUEST_URI'])) {
			return null;
		}

		$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
		$host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field($_SERVER['HTTP_HOST']) : '';
		$uri = sanitize_text_field($_SERVER['REQUEST_URI']);

		return $protocol . '://' . $host . $uri;
	}
}

/**
 * Get logger instance (convenience function)
 *
 * @return LB_Logger
 */
function leadbox_logger()
{
	return LB_Logger::getInstance();
}