Server IP : 104.21.14.48 / Your IP : 3.138.68.71 [ Web Server : Apache System : Linux b70eb322-3aee-0c53-7c82-0db91281f2c6.secureserver.net 6.1.90-1.el9.elrepo.x86_64 #1 SMP PREEMPT_DYNAMIC Thu May 2 12:09:22 EDT 2024 x86_64 User : root ( 0) PHP Version : 8.0.30.2 Disable Function : NONE Domains : 0 Domains MySQL : ON | cURL : ON | WGET : ON | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /var/www/wp-content/mu-plugins/object-cache-pro/src/Extensions/QueryMonitor/ |
Upload File : |
<?php /** * Copyright © 2019-2024 Rhubarb Tech Inc. All Rights Reserved. * * The Object Cache Pro Software and its related materials are property and confidential * information of Rhubarb Tech Inc. Any reproduction, use, distribution, or exploitation * of the Object Cache Pro Software and its related materials, in whole or in part, * is strictly forbidden unless prior permission is obtained from Rhubarb Tech Inc. * * In addition, any reproduction, use, distribution, or exploitation of the Object Cache Pro * Software and its related materials, in whole or in part, is subject to the End-User License * Agreement accessible in the included `LICENSE` file, or at: https://objectcache.pro/eula */ declare(strict_types=1); namespace RedisCachePro\Extensions\QueryMonitor; use QM_Backtrace; use QM_Collector; use RedisCachePro\Loggers\ArrayLogger; use RedisCachePro\Connections\Connection; use RedisCachePro\Connections\Transaction; use RedisCachePro\Connections\RelayConnection; use RedisCachePro\Connections\PhpRedisConnection; use RedisCachePro\ObjectCaches\ObjectCache; use RedisCachePro\ObjectCaches\RelayObjectCache; use RedisCachePro\ObjectCaches\PhpRedisObjectCache; class CommandsCollector extends QM_Collector { /** * Holds the ID of the collector. * * @var string */ public $id = 'cache-commands'; /** * Ignored methods in all object cache classes. * * @var array<string, bool> */ const IgnoredMethods = [ 'add' => true, 'add_multiple' => true, 'set' => true, 'set_multiple' => true, 'get' => true, 'get_multiple' => true, 'decr' => true, 'incr' => true, 'info' => true, 'flush' => true, 'write' => true, 'multiwrite' => true, 'delete' => true, 'delete_multiple' => true, 'replace' => true, 'getAllOptions' => true, 'syncAllOptions' => true, 'deleteAllOptions' => true, 'withoutMutations' => true, ]; /** * Ignored functions. * * @var array<string, bool> */ const IgnoredFunctions = [ 'wp_cache_add' => true, 'wp_cache_add_multiple' => true, 'wp_cache_get' => true, 'wp_cache_get_multiple' => true, 'wp_cache_get_last_changed' => true, 'wp_cache_set' => true, 'wp_cache_set_multiple' => true, 'wp_cache_decr' => true, 'wp_cache_incr' => true, 'wp_cache_sear' => true, 'wp_cache_flush' => true, 'wp_cache_flush_group' => true, 'wp_cache_delete' => true, 'wp_cache_delete_multiple' => true, 'wp_cache_replace' => true, 'wp_cache_remember' => true, 'wp_cache_switch_to_blog' => true, 'wp_cache_add_global_groups' => true, 'wp_cache_add_non_persistent_groups' => true, 'set_transient' => true, 'get_transient' => true, 'get_site_transient' => true, 'get_option' => true, 'get_site_option' => true, 'get_network_option' => true, ]; /** * Returns the collector name. * * Obsolete since Query Monitor 3.5.0. * * @return string */ public function name() { return 'Commands'; } /** * Populate the `data` property. * * @return void */ public function process() { global $wp_object_cache; if (! $wp_object_cache instanceof ObjectCache) { return; } $logger = $wp_object_cache->logger(); if (! $logger instanceof ArrayLogger) { $this->data['commands'] = []; return; } $backtraces = defined('\QM_VERSION') && version_compare(constant('\QM_VERSION'), '3.8.1', '>='); $this->data['commands'] = $this->buildCommands($logger, $backtraces); $types = array_unique(array_column($this->data['commands'], 'command')); $types = array_map('strtoupper', $types); sort($types); $this->data['types'] = $types; if ($backtraces) { $components = array_map(static function ($command) { return $command['backtrace']->get_component()->name; }, $this->data['commands']); $this->data['components'] = array_unique($components); } } /** * Builds the array of Redis commands. * * @param \RedisCachePro\Loggers\ArrayLogger $logger * @param bool $backtraces * @return array<int, array<string, mixed>> */ protected function buildCommands(ArrayLogger $logger, bool $backtraces) { $commands = []; $backtraceArgs = $this->buildBacktraceArgs(); foreach ($logger->messages() as $message) { $command = $message['context']['command'] ?? 'UNKNOWN'; if ($command === 'RAWCOMMAND') { $command = array_shift($message['context']['parameters']); if (is_array($command)) { $node = $command; $command = array_shift($message['context']['parameters']); array_unshift($message['context']['parameters'], $node); } } $commands[] = [ 'level' => $message['level'], 'time' => $message['context']['time'] ?? 0, 'bytes' => $message['context']['memory'] ?? 0, 'command' => $command, 'parameters' => $this->formatParameters( $message['context']['parameters'] ?? [] ), 'backtrace' => $backtraces ? new QM_Backtrace($backtraceArgs, $message['context']['backtrace'] ?? null) : null, ]; } return $commands; } /** * Builds the backtrace arguments for `QM_Backtrace`. * * @return array<string, mixed> */ protected function buildBacktraceArgs() { global $wp_object_cache; $connection = $wp_object_cache->connection() ? get_class($wp_object_cache->connection()) : null; return [ 'ignore_class' => array_filter([ // @phpstan-ignore-line Connection::class => true, Transaction::class => true, RelayConnection::class => true, PhpRedisConnection::class => true, $connection => true, ]), 'ignore_method' => [ ObjectCache::class => self::IgnoredMethods, RelayObjectCache::class => self::IgnoredMethods, PhpRedisObjectCache::class => self::IgnoredMethods, get_class($wp_object_cache) => self::IgnoredMethods, ], 'ignore_func' => self::IgnoredFunctions, ]; } /** * Converts all parameter values to JSON and trims them down to 200 characters or less. * * @param array<mixed> $parameters * @return array<mixed> */ protected function formatParameters($parameters) { $format = static function ($value) { return stripslashes((string) json_encode( $value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT )); }; return array_map(static function ($parameter) use ($format) { $value = is_object($parameter) ? get_class($parameter) . $format($parameter) : $format($parameter); $value = preg_replace('/\s+/', ' ', (string) $value); $value = trim($value, '"'); if (strlen($value) > 200) { return substr($value, 0, 200) . '...'; } return $value; }, $parameters); } }