Files
profile/inc/realtime-debug.php

222 lines
7.4 KiB
PHP
Raw Permalink Normal View History

2026-03-09 20:51:08 +03:00
<?php
/**
* Real-time Execution Logger for WordPress
* Логирует выполнение страницы в реальном времени
*/
class RealtimePageLogger {
private static $instance;
private $log_file;
private $request_id;
private $start_time;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->log_file = WP_CONTENT_DIR . '/realtime-debug.log';
$this->request_id = uniqid('req_', true);
$this->start_time = microtime(true);
// Очищаем файл при инициализации
$this->clean_log_file();
$this->init();
}
/**
* Очистка лог-файла с проверками
*/
private function clean_log_file() {
// Если файл не существует, создаем его
if (!file_exists($this->log_file)) {
if (touch($this->log_file)) {
chmod($this->log_file, 0644);
$this->log_message("Создан новый лог-файл", 'SYSTEM');
} else {
error_log('Не удалось создать файл realtime-debug.log');
return;
}
}
// Проверяем доступность для записи
if (!is_writable($this->log_file)) {
error_log('Файл realtime-debug.log недоступен для записи');
return;
}
// Очищаем файл
if (file_put_contents($this->log_file, '') === false) {
error_log('Не удалось очистить файл realtime-debug.log');
} else {
$this->log_message("Лог-файл очищен", 'SYSTEM');
}
}
private function init() {
// Начинаем логирование как можно раньше
add_action('plugins_loaded', [$this, 'log_plugins_loaded'], 1);
add_action('setup_theme', [$this, 'log_setup_theme'], 1);
add_action('after_setup_theme', [$this, 'log_after_setup_theme'], 1);
add_action('init', [$this, 'log_init'], 1);
// Логируем все основные этапы
add_action('wp_loaded', [$this, 'log_wp_loaded']);
add_action('parse_query', [$this, 'log_parse_query']);
add_action('pre_get_posts', [$this, 'log_pre_get_posts']);
add_action('wp', [$this, 'log_wp']);
// Логируем SQL запросы
add_filter('query', [$this, 'log_sql_query']);
// Логируем шаблоны
add_filter('template_include', [$this, 'log_template_include'], 9999);
// Логируем завершение
add_action('shutdown', [$this, 'log_shutdown'], 9999);
// Логируем хуки в реальном времени
$this->setup_hook_logging();
}
public function setup_hook_logging() {
$important_hooks = [
'template_redirect',
'get_header',
'wp_head',
'the_post',
'loop_start',
'loop_end',
'get_sidebar',
'get_footer',
'wp_footer',
'admin_bar_menu',
'wp_enqueue_scripts',
'wp_print_styles',
'wp_print_scripts'
];
foreach ($important_hooks as $hook) {
add_action($hook, function() use ($hook) {
$this->log_hook($hook);
}, 1);
}
}
private function log_message($message, $level = 'INFO') {
$timestamp = microtime(true);
$elapsed = round(($timestamp - $this->start_time) * 1000, 2);
$memory = memory_get_usage(true);
$log = sprintf(
"[%s] %s | %6.2fms | %8s | %s | %s\n",
date('H:i:s'),
$this->request_id,
$elapsed,
size_format($memory, 0),
$level,
$message
);
file_put_contents($this->log_file, $log, FILE_APPEND);
}
public function log_plugins_loaded() {
$this->log_message('PLUGINS_LOADED - Плагины загружены');
}
public function log_setup_theme() {
$this->log_message('SETUP_THEME - Начинается загрузка темы');
}
public function log_after_setup_theme() {
$this->log_message('AFTER_SETUP_THEME - Тема загружена');
}
public function log_init() {
$this->log_message('INIT - WordPress инициализирован');
}
public function log_wp_loaded() {
$this->log_message('WP_LOADED - WordPress полностью загружен');
}
public function log_parse_query() {
global $wp_query;
$this->log_message(sprintf('PARSE_QUERY - Запрос: %s', $wp_query->query_vars['pagename'] ?? 'main'));
}
public function log_pre_get_posts($query) {
if ($query->is_main_query()) {
$this->log_message('PRE_GET_POSTS - Основной запрос к posts');
}
}
public function log_wp() {
$this->log_message('WP - Запрос обработан, готовим данные для шаблона');
}
public function log_sql_query($query) {
$trimmed = trim($query);
if (!empty($trimmed) && !str_starts_with($trimmed, '/*')) {
//$short_query = substr($trimmed, 0, 150);
//if (strlen($trimmed) > 150) {
// $short_query .= '...';
// }
$this->log_message("SQL: {$query}", 'SQL');
}
return $query;
}
public function log_hook($hook) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 4);
$caller = $this->get_caller_info($backtrace);
$this->log_message("HOOK: {$hook}{$caller}", 'HOOK');
}
public function log_template_include($template) {
$template_name = basename($template);
$this->log_message("TEMPLATE: {$template_name}", 'TEMPLATE');
return $template;
}
public function log_shutdown() {
$total_time = round((microtime(true) - $this->start_time) * 1000, 2);
$peak_memory = memory_get_peak_usage(true);
$this->log_message("SHUTDOWN - Завершение работы ({$total_time}ms, " .
size_format($peak_memory) . ")", 'FINISH');
}
private function get_caller_info($backtrace) {
foreach ($backtrace as $trace) {
if (isset($trace['file']) &&
!str_contains($trace['file'], 'wp-includes') &&
!str_contains($trace['file'], 'wp-admin')) {
$file = basename($trace['file']);
$line = $trace['line'] ?? 'unknown';
return "{$file}:{$line}";
}
}
return 'unknown';
}
}
// Инициализируем логгер только если включен дебаг
//if (defined('WP_DEBUG') && WP_DEBUG) {
RealtimePageLogger::get_instance();
//}
// Функция для очистки лога
add_action('wp_ajax_clear_realtime_log', 'clear_realtime_debug_log');
function clear_realtime_debug_log() {
if (current_user_can('administrator')) {
file_put_contents(WP_CONTENT_DIR . '/realtime-debug.log', '');
echo "Realtime log cleared!";
}
wp_die();
}