Files
care-book-block-ultimate/PRODUCTION-READY/care-booking-block-ultimate/includes/class-performance-monitor.php
Emanuel Almeida 38bb926742 chore: add spec-kit and standardize signatures
- Added GitHub spec-kit for development workflow
- Standardized file signatures to Descomplicar® format
- Updated development configuration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-12 01:27:34 +01:00

537 lines
18 KiB
PHP

/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php
/**
* Performance Monitor for Care Booking Block plugin
* Tracks and analyzes performance metrics to ensure <2% overhead target
*
* @package CareBookingBlock
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
/**
* Performance Monitor class for enterprise-grade optimization
*/
class Care_Booking_Performance_Monitor
{
/**
* Performance metrics cache key
*/
const METRICS_CACHE_KEY = 'care_booking_performance_metrics';
/**
* Performance target: <2% overhead
*/
const TARGET_OVERHEAD_PERCENT = 2.0;
/**
* Performance target: <100ms AJAX response
*/
const TARGET_AJAX_RESPONSE_MS = 100;
/**
* Performance target: >95% cache hit rate
*/
const TARGET_CACHE_HIT_RATE = 95.0;
/**
* Initialize performance monitoring
*/
public static function init()
{
// Hook into WordPress performance points
add_action('init', [__CLASS__, 'start_performance_tracking'], 1);
add_action('wp_footer', [__CLASS__, 'end_performance_tracking'], 999);
// AJAX performance tracking
add_action('wp_ajax_care_booking_get_entities', [__CLASS__, 'track_ajax_start'], 1);
add_action('wp_ajax_nopriv_care_booking_get_entities', [__CLASS__, 'track_ajax_start'], 1);
// Database query performance
add_filter('query', [__CLASS__, 'track_database_queries'], 10, 1);
// Cache performance tracking
add_action('care_booking_cache_hit', [__CLASS__, 'track_cache_hit']);
add_action('care_booking_cache_miss', [__CLASS__, 'track_cache_miss']);
// Memory usage tracking
add_action('shutdown', [__CLASS__, 'track_memory_usage'], 1);
}
/**
* Start performance tracking for page loads
*/
public static function start_performance_tracking()
{
if (!self::should_track_performance()) {
return;
}
// Store start time and memory
if (!defined('CARE_BOOKING_START_TIME')) {
define('CARE_BOOKING_START_TIME', microtime(true));
define('CARE_BOOKING_START_MEMORY', memory_get_usage());
}
}
/**
* End performance tracking and calculate metrics
*/
public static function end_performance_tracking()
{
if (!defined('CARE_BOOKING_START_TIME')) {
return;
}
$end_time = microtime(true);
$end_memory = memory_get_usage();
$execution_time = ($end_time - CARE_BOOKING_START_TIME) * 1000; // Convert to ms
$memory_usage = $end_memory - CARE_BOOKING_START_MEMORY;
// Calculate overhead percentage (plugin time vs total page time)
$total_page_time = (microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000;
$overhead_percent = ($execution_time / $total_page_time) * 100;
$metrics = [
'execution_time_ms' => round($execution_time, 2),
'memory_usage_bytes' => $memory_usage,
'overhead_percent' => round($overhead_percent, 2),
'timestamp' => time(),
'url' => $_SERVER['REQUEST_URI'] ?? '',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? ''
];
self::store_performance_metrics($metrics);
self::check_performance_targets($metrics);
// Output debug info if enabled
if (defined('WP_DEBUG') && WP_DEBUG && current_user_can('manage_options')) {
self::output_debug_info($metrics);
}
}
/**
* Track AJAX request start time
*/
public static function track_ajax_start()
{
if (!defined('CARE_BOOKING_AJAX_START')) {
define('CARE_BOOKING_AJAX_START', microtime(true));
}
}
/**
* Track AJAX response completion
*
* @param mixed $response AJAX response data
* @return mixed Original response
*/
public static function track_ajax_complete($response)
{
if (!defined('CARE_BOOKING_AJAX_START')) {
return $response;
}
$response_time = (microtime(true) - CARE_BOOKING_AJAX_START) * 1000;
$metrics = [
'ajax_response_time_ms' => round($response_time, 2),
'ajax_action' => $_POST['action'] ?? '',
'timestamp' => time()
];
self::store_ajax_metrics($metrics);
// Check if we're meeting AJAX performance targets
if ($response_time > self::TARGET_AJAX_RESPONSE_MS) {
self::log_performance_warning("AJAX response exceeded target: {$response_time}ms > " . self::TARGET_AJAX_RESPONSE_MS . "ms");
}
return $response;
}
/**
* Track database queries performance
*
* @param string $query SQL query
* @return string Original query
*/
public static function track_database_queries($query)
{
// Only track Care Booking related queries
if (strpos($query, 'care_booking_restrictions') === false) {
return $query;
}
$start_time = microtime(true);
// Use a filter to track completion
add_filter('query_result', function($result) use ($start_time, $query) {
$execution_time = (microtime(true) - $start_time) * 1000;
if ($execution_time > 50) { // Log slow queries > 50ms
self::log_performance_warning("Slow query detected: {$execution_time}ms - " . substr($query, 0, 100));
}
return $result;
}, 10, 1);
return $query;
}
/**
* Track cache hit
*
* @param string $cache_key Cache key that was hit
*/
public static function track_cache_hit($cache_key = '')
{
$stats = get_transient('care_booking_cache_stats') ?: ['hits' => 0, 'misses' => 0];
$stats['hits']++;
$stats['last_hit'] = time();
set_transient('care_booking_cache_stats', $stats, HOUR_IN_SECONDS);
}
/**
* Track cache miss
*
* @param string $cache_key Cache key that was missed
*/
public static function track_cache_miss($cache_key = '')
{
$stats = get_transient('care_booking_cache_stats') ?: ['hits' => 0, 'misses' => 0];
$stats['misses']++;
$stats['last_miss'] = time();
set_transient('care_booking_cache_stats', $stats, HOUR_IN_SECONDS);
// Log excessive cache misses
$total = $stats['hits'] + $stats['misses'];
if ($total > 10 && (($stats['hits'] / $total) * 100) < self::TARGET_CACHE_HIT_RATE) {
self::log_performance_warning("Cache hit rate below target: " . round(($stats['hits'] / $total) * 100, 1) . "%");
}
}
/**
* Track memory usage
*/
public static function track_memory_usage()
{
$current_memory = memory_get_usage();
$peak_memory = memory_get_peak_usage();
// Target: <10MB footprint
$target_memory = 10 * 1024 * 1024; // 10MB in bytes
if (defined('CARE_BOOKING_START_MEMORY')) {
$plugin_memory = $current_memory - CARE_BOOKING_START_MEMORY;
if ($plugin_memory > $target_memory) {
self::log_performance_warning("Memory usage exceeded target: " . size_format($plugin_memory) . " > 10MB");
}
}
}
/**
* Store performance metrics
*
* @param array $metrics Performance metrics
*/
private static function store_performance_metrics($metrics)
{
$stored_metrics = get_transient(self::METRICS_CACHE_KEY) ?: [];
// Keep only last 100 measurements for performance
if (count($stored_metrics) >= 100) {
$stored_metrics = array_slice($stored_metrics, -99);
}
$stored_metrics[] = $metrics;
set_transient(self::METRICS_CACHE_KEY, $stored_metrics, DAY_IN_SECONDS);
}
/**
* Store AJAX performance metrics
*
* @param array $metrics AJAX metrics
*/
private static function store_ajax_metrics($metrics)
{
$ajax_metrics = get_transient('care_booking_ajax_metrics') ?: [];
if (count($ajax_metrics) >= 50) {
$ajax_metrics = array_slice($ajax_metrics, -49);
}
$ajax_metrics[] = $metrics;
set_transient('care_booking_ajax_metrics', $ajax_metrics, DAY_IN_SECONDS);
}
/**
* Check if performance targets are being met
*
* @param array $metrics Current performance metrics
*/
private static function check_performance_targets($metrics)
{
$warnings = [];
// Check overhead target (<2%)
if ($metrics['overhead_percent'] > self::TARGET_OVERHEAD_PERCENT) {
$warnings[] = "Page overhead exceeded target: {$metrics['overhead_percent']}% > " . self::TARGET_OVERHEAD_PERCENT . "%";
}
// Check execution time target (<50ms for plugin operations)
if ($metrics['execution_time_ms'] > 50) {
$warnings[] = "Plugin execution time high: {$metrics['execution_time_ms']}ms";
}
// Check memory usage target (<10MB)
$memory_mb = $metrics['memory_usage_bytes'] / (1024 * 1024);
if ($memory_mb > 10) {
$warnings[] = "Memory usage exceeded target: " . round($memory_mb, 2) . "MB > 10MB";
}
foreach ($warnings as $warning) {
self::log_performance_warning($warning);
}
}
/**
* Log performance warning
*
* @param string $message Warning message
*/
private static function log_performance_warning($message)
{
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
error_log("Care Booking Performance Warning: " . $message);
}
// Store in admin notices if user is admin
if (current_user_can('manage_options')) {
$notices = get_transient('care_booking_performance_notices') ?: [];
$notices[] = [
'message' => $message,
'timestamp' => time(),
'severity' => 'warning'
];
// Keep only last 10 notices
if (count($notices) > 10) {
$notices = array_slice($notices, -10);
}
set_transient('care_booking_performance_notices', $notices, HOUR_IN_SECONDS);
}
}
/**
* Get comprehensive performance report
*
* @return array Performance report
*/
public static function get_performance_report()
{
$metrics = get_transient(self::METRICS_CACHE_KEY) ?: [];
$ajax_metrics = get_transient('care_booking_ajax_metrics') ?: [];
$cache_stats = get_transient('care_booking_cache_stats') ?: ['hits' => 0, 'misses' => 0];
if (empty($metrics)) {
return ['status' => 'no_data'];
}
// Calculate averages
$avg_overhead = array_sum(array_column($metrics, 'overhead_percent')) / count($metrics);
$avg_execution = array_sum(array_column($metrics, 'execution_time_ms')) / count($metrics);
$avg_memory = array_sum(array_column($metrics, 'memory_usage_bytes')) / count($metrics);
// Calculate cache hit rate
$total_cache_requests = $cache_stats['hits'] + $cache_stats['misses'];
$cache_hit_rate = $total_cache_requests > 0 ? ($cache_stats['hits'] / $total_cache_requests) * 100 : 0;
// Calculate AJAX averages
$avg_ajax_response = !empty($ajax_metrics)
? array_sum(array_column($ajax_metrics, 'ajax_response_time_ms')) / count($ajax_metrics)
: 0;
return [
'status' => 'active',
'targets' => [
'overhead_percent' => self::TARGET_OVERHEAD_PERCENT,
'ajax_response_ms' => self::TARGET_AJAX_RESPONSE_MS,
'cache_hit_rate' => self::TARGET_CACHE_HIT_RATE
],
'current' => [
'avg_overhead_percent' => round($avg_overhead, 2),
'avg_execution_time_ms' => round($avg_execution, 2),
'avg_memory_usage_mb' => round($avg_memory / (1024 * 1024), 2),
'cache_hit_rate_percent' => round($cache_hit_rate, 2),
'avg_ajax_response_ms' => round($avg_ajax_response, 2)
],
'performance_score' => self::calculate_performance_score($avg_overhead, $avg_ajax_response, $cache_hit_rate),
'measurements_count' => count($metrics),
'last_measurement' => max(array_column($metrics, 'timestamp'))
];
}
/**
* Calculate overall performance score (0-100)
*
* @param float $overhead_percent Current overhead percentage
* @param float $ajax_response_ms Current AJAX response time
* @param float $cache_hit_rate Current cache hit rate
* @return int Performance score
*/
private static function calculate_performance_score($overhead_percent, $ajax_response_ms, $cache_hit_rate)
{
$score = 100;
// Deduct points for overhead (target <2%)
if ($overhead_percent > self::TARGET_OVERHEAD_PERCENT) {
$score -= min(30, ($overhead_percent - self::TARGET_OVERHEAD_PERCENT) * 10);
}
// Deduct points for AJAX response time (target <100ms)
if ($ajax_response_ms > self::TARGET_AJAX_RESPONSE_MS) {
$score -= min(30, ($ajax_response_ms - self::TARGET_AJAX_RESPONSE_MS) / 10);
}
// Deduct points for cache hit rate (target >95%)
if ($cache_hit_rate < self::TARGET_CACHE_HIT_RATE) {
$score -= min(25, (self::TARGET_CACHE_HIT_RATE - $cache_hit_rate));
}
return max(0, (int) $score);
}
/**
* Should track performance based on current context
*
* @return bool True if should track
*/
private static function should_track_performance()
{
// Don't track in admin area unless specifically enabled
if (is_admin() && !defined('CARE_BOOKING_TRACK_ADMIN_PERFORMANCE')) {
return false;
}
// Don't track for bots and crawlers
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (preg_match('/bot|crawler|spider|robot/i', $user_agent)) {
return false;
}
return true;
}
/**
* Output debug information
*
* @param array $metrics Performance metrics
*/
private static function output_debug_info($metrics)
{
echo "\n<!-- Care Booking Performance Debug -->\n";
echo "<!-- Execution Time: {$metrics['execution_time_ms']}ms -->\n";
echo "<!-- Memory Usage: " . size_format($metrics['memory_usage_bytes']) . " -->\n";
echo "<!-- Page Overhead: {$metrics['overhead_percent']}% -->\n";
echo "<!-- Target Overhead: " . self::TARGET_OVERHEAD_PERCENT . "% -->\n";
$status = $metrics['overhead_percent'] <= self::TARGET_OVERHEAD_PERCENT ? 'MEETING TARGET' : 'EXCEEDING TARGET';
echo "<!-- Performance Status: {$status} -->\n";
echo "<!-- End Care Booking Performance Debug -->\n";
}
/**
* Get performance notices for admin display
*
* @return array Performance notices
*/
public static function get_performance_notices()
{
return get_transient('care_booking_performance_notices') ?: [];
}
/**
* Clear performance notices
*/
public static function clear_performance_notices()
{
delete_transient('care_booking_performance_notices');
}
/**
* Get asset optimization statistics
*
* @return array Asset optimization stats
*/
public static function get_asset_stats()
{
$asset_files = [
'admin_css' => [
'original' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'admin/css/admin-style.css',
'minified' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'admin/css/admin-style.min.css'
],
'admin_js' => [
'original' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'admin/js/admin-script.js',
'minified' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'admin/js/admin-script.min.js'
],
'frontend_css' => [
'original' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/css/frontend.css',
'minified' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/css/frontend.min.css'
],
'frontend_js' => [
'original' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/js/frontend.js',
'minified' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/js/frontend.min.js'
]
];
$stats = [];
$total_original = 0;
$total_minified = 0;
foreach ($asset_files as $key => $files) {
$original_size = file_exists($files['original']) ? filesize($files['original']) : 0;
$minified_size = file_exists($files['minified']) ? filesize($files['minified']) : 0;
$savings_bytes = $original_size - $minified_size;
$savings_percent = $original_size > 0 ? ($savings_bytes / $original_size) * 100 : 0;
$stats[$key] = [
'original_size' => $original_size,
'minified_size' => $minified_size,
'savings_bytes' => $savings_bytes,
'savings_percent' => round($savings_percent, 1)
];
$total_original += $original_size;
$total_minified += $minified_size;
}
$total_savings = $total_original - $total_minified;
$total_savings_percent = $total_original > 0 ? ($total_savings / $total_original) * 100 : 0;
$stats['total'] = [
'original_size' => $total_original,
'minified_size' => $total_minified,
'savings_bytes' => $total_savings,
'savings_percent' => round($total_savings_percent, 1)
];
return $stats;
}
}
// Initialize performance monitoring
add_action('plugins_loaded', [Care_Booking_Performance_Monitor::class, 'init'], 5);