Files
roi-theme/wp-content/plugins/wp-debug/inc/logger.php

336 lines
9.1 KiB
PHP

<?php
/**
* Logger Module
*
* Sistema de logging centralizado con soporte para archivos y base de datos
*
* @package WP_Debug
* @since 1.0.0
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
/**
* WP_Debug_Logger class
*/
class WP_Debug_Logger {
/**
* Log levels
*/
const LEVEL_INFO = 'INFO';
const LEVEL_WARNING = 'WARNING';
const LEVEL_ERROR = 'ERROR';
const LEVEL_DEBUG = 'DEBUG';
/**
* Log file handle
*
* @var resource
*/
private static $file_handle = null;
/**
* Initialize logger
*/
public static function init() {
// Hook into shutdown to close file handle
add_action('shutdown', array(__CLASS__, 'close_file_handle'));
}
/**
* Log a message
*
* @param string $message Message to log
* @param string $level Log level
* @param array $context Additional context
* @return bool True on success
*/
public static function log($message, $level = self::LEVEL_INFO, $context = array()) {
// Check if logging is enabled
if (!get_option('wp_debug_enabled', true)) {
return false;
}
// Validate level
if (!in_array($level, array(self::LEVEL_INFO, self::LEVEL_WARNING, self::LEVEL_ERROR, self::LEVEL_DEBUG))) {
$level = self::LEVEL_INFO;
}
// Get current log level setting
$min_level = get_option('wp_debug_log_level', self::LEVEL_INFO);
if (!self::should_log($level, $min_level)) {
return false;
}
// Prepare log entry
$log_entry = self::prepare_log_entry($message, $level, $context);
// Log to file
$log_to_file = get_option('wp_debug_log_to_file', true);
if ($log_to_file) {
self::log_to_file($log_entry);
}
// Log to database
$log_to_db = get_option('wp_debug_log_to_db', true);
if ($log_to_db) {
self::log_to_database($log_entry);
}
return true;
}
/**
* Check if message should be logged based on level
*
* @param string $level Message level
* @param string $min_level Minimum level to log
* @return bool True if should log
*/
private static function should_log($level, $min_level) {
$levels = array(
self::LEVEL_DEBUG => 0,
self::LEVEL_INFO => 1,
self::LEVEL_WARNING => 2,
self::LEVEL_ERROR => 3,
);
return $levels[$level] >= $levels[$min_level];
}
/**
* Prepare log entry with all context
*
* @param string $message Message
* @param string $level Level
* @param array $context Context
* @return array Log entry
*/
private static function prepare_log_entry($message, $level, $context) {
$user = wp_get_current_user();
return array(
'timestamp' => current_time('mysql'),
'level' => $level,
'message' => $message,
'context' => !empty($context) ? json_encode($context) : null,
'user_id' => $user->ID,
'url' => isset($_SERVER['REQUEST_URI']) ? esc_url_raw($_SERVER['REQUEST_URI']) : '',
'ip_address' => self::get_client_ip(),
'backtrace' => self::get_backtrace(),
);
}
/**
* Log to file
*
* @param array $log_entry Log entry
* @return bool True on success
*/
private static function log_to_file($log_entry) {
$logs_dir = WP_CONTENT_DIR . '/logs/wp-debug';
$log_file = $logs_dir . '/debug-' . date('Y-m-d') . '.log';
// Ensure directory exists
if (!file_exists($logs_dir)) {
wp_mkdir_p($logs_dir);
}
// Prepare log line
$log_line = sprintf(
"[%s] [%s] %s | User: %s | URL: %s | IP: %s\n",
$log_entry['timestamp'],
$log_entry['level'],
$log_entry['message'],
$log_entry['user_id'],
$log_entry['url'],
$log_entry['ip_address']
);
// Add context if exists
if ($log_entry['context']) {
$log_line .= sprintf(" Context: %s\n", $log_entry['context']);
}
// Add backtrace if exists
if ($log_entry['backtrace']) {
$log_line .= sprintf(" Backtrace: %s\n", $log_entry['backtrace']);
}
// Write to file
return file_put_contents($log_file, $log_line, FILE_APPEND | LOCK_EX) !== false;
}
/**
* Log to database
*
* @param array $log_entry Log entry
* @return bool True on success
*/
private static function log_to_database($log_entry) {
global $wpdb;
$table = $wpdb->prefix . 'wp_debug_logs';
return $wpdb->insert(
$table,
array(
'timestamp' => $log_entry['timestamp'],
'level' => $log_entry['level'],
'message' => $log_entry['message'],
'context' => $log_entry['context'],
'user_id' => $log_entry['user_id'],
'url' => $log_entry['url'],
'ip_address' => $log_entry['ip_address'],
),
array('%s', '%s', '%s', '%s', '%d', '%s', '%s')
) !== false;
}
/**
* Get client IP address
*
* @return string IP address
*/
private static function get_client_ip() {
$ip = '';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
return sanitize_text_field($ip);
}
/**
* Get backtrace
*
* @return string Backtrace string
*/
private static function get_backtrace() {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5);
$trace_string = '';
foreach ($backtrace as $index => $trace) {
if (isset($trace['file']) && isset($trace['line'])) {
$trace_string .= sprintf(
"%s:%s",
basename($trace['file']),
$trace['line']
);
if ($index < count($backtrace) - 1) {
$trace_string .= ' -> ';
}
}
}
return $trace_string;
}
/**
* Get logs from database
*
* @param array $args Query arguments
* @return array Logs
*/
public static function get_logs($args = array()) {
global $wpdb;
$defaults = array(
'level' => null,
'limit' => 100,
'offset' => 0,
'orderby' => 'timestamp',
'order' => 'DESC',
);
$args = wp_parse_args($args, $defaults);
$table = $wpdb->prefix . 'wp_debug_logs';
$where = '1=1';
if ($args['level']) {
$where .= $wpdb->prepare(' AND level = %s', $args['level']);
}
$query = $wpdb->prepare(
"SELECT * FROM {$table} WHERE {$where} ORDER BY {$args['orderby']} {$args['order']} LIMIT %d OFFSET %d",
$args['limit'],
$args['offset']
);
return $wpdb->get_results($query);
}
/**
* Clear old logs
*
* @param int $days Days to keep
* @return bool True on success
*/
public static function clear_old_logs($days = null) {
if ($days === null) {
$days = get_option('wp_debug_log_retention_days', 7);
}
// Clear database logs
global $wpdb;
$table = $wpdb->prefix . 'wp_debug_logs';
$date = date('Y-m-d H:i:s', strtotime("-{$days} days"));
$wpdb->query($wpdb->prepare("DELETE FROM {$table} WHERE timestamp < %s", $date));
// Clear file logs
$logs_dir = WP_CONTENT_DIR . '/logs/wp-debug';
if (file_exists($logs_dir)) {
$files = glob($logs_dir . '/debug-*.log');
$cutoff = strtotime("-{$days} days");
foreach ($files as $file) {
if (filemtime($file) < $cutoff) {
unlink($file);
}
}
}
return true;
}
/**
* Close file handle on shutdown
*/
public static function close_file_handle() {
if (self::$file_handle) {
fclose(self::$file_handle);
self::$file_handle = null;
}
}
/**
* Convenience methods for different log levels
*/
public static function info($message, $context = array()) {
return self::log($message, self::LEVEL_INFO, $context);
}
public static function warning($message, $context = array()) {
return self::log($message, self::LEVEL_WARNING, $context);
}
public static function error($message, $context = array()) {
return self::log($message, self::LEVEL_ERROR, $context);
}
public static function debug($message, $context = array()) {
return self::log($message, self::LEVEL_DEBUG, $context);
}
}