File: /var/www/wp-content/mu-plugins/object-cache-pro/src/Console/Watchers/DigestWatcher.php
<?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\Console\Watchers;
use WP_CLI;
use WP_CLI\Formatter;
use cli\Notify;
use cli\Streams;
use RedisCachePro\Metrics\Measurements;
class DigestWatcher extends Notify
{
/**
* Holds the command options.
*
* @var array<mixed>
*/
public $options;
/**
* The object cache instance.
*
* @var \RedisCachePro\ObjectCaches\MeasuredObjectCacheInterface
*/
public $cache;
/**
* Whether Relay is being used.
*
* @var bool
*/
public $usingRelay;
/**
* The calculated metric items.
*
* @var array<mixed>|null
*/
protected $items;
/**
* The characters used for the spinner.
*
* @var string
*/
protected $chars = '-\|/';
/**
* Holds the current iteration.
*
* @var int
*/
protected $iteration = 0;
/**
* Holds the default metrics.
*
* @var array<string>
*/
protected $defaultMetrics = [
'ms-total',
'ms-cache',
'ms-cache-avg',
'ms-cache-ratio',
'hits',
'misses',
'hit-ratio',
'store-reads',
'store-writes',
'sql-queries',
'redis-hit-ratio',
'redis-ops-per-sec',
'redis-keys',
'relay-hits',
'relay-keys',
'relay-misses',
'relay-memory-human',
];
/**
* Prints the metrics table to the screen.
*
* @param bool $finish
* @return void
*/
public function display($finish = false)
{
$idx = $this->iteration++ % 4;
$lines = 4 + count($this->items);
$arguments = ['format' => 'table'];
$fields = ['Metric', 'Median'];
ob_start();
$formatter = new Formatter($arguments, $fields);
$formatter->display_items($this->items, true);
Streams::out((string) ob_get_clean());
Streams::out(WP_CLI::colorize('{:msg} %g{:char}%n'), [
'msg' => WP_CLI::colorize($this->_message),
'char' => $this->chars[$idx],
]);
Streams::out("\e[{$lines}A");
Streams::out("\e[0G");
}
/**
* Prepare the metrics.
*
* @return void
*/
public function prepare()
{
$this->items = null;
$metrics = empty($this->options['metrics'])
? $this->defaultMetrics
: $this->options['metrics'];
$measurements = $this->cache->measurements(
strval(microtime(true) - $this->options['seconds'])
);
foreach ($metrics as $metric) {
$method = 'get' . str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $metric)));
if (! method_exists($this, $method)) {
WP_CLI::error("Invalid metric name: {$metric}.");
}
$item = $this->{$method}($measurements);
$item->Median = str_pad((string) $item->Median, 20, ' ', STR_PAD_LEFT);
$this->items[] = $item;
}
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getHits(Measurements $measurements)
{
$hitsMedian = $measurements->median('wp->hits');
return (object) [
'Metric' => WP_CLI::colorize('%bCache%n: Hits'),
'Median' => is_null($hitsMedian) ? '' : number_format($hitsMedian),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getMisses(Measurements $measurements)
{
$missesMedian = $measurements->median('wp->misses');
return (object) [
'Metric' => WP_CLI::colorize('%bCache%n: Misses'),
'Median' => is_null($missesMedian) ? '' : number_format($missesMedian),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getHitRatio(Measurements $measurements)
{
$hitRatioMedian = $measurements->median('wp->hitRatio');
return (object) [
'Metric' => WP_CLI::colorize('%bCache%n: Hit ratio'),
'Median' => is_null($hitRatioMedian) ? '' : number_format($hitRatioMedian, 1) . '%',
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getBytes(Measurements $measurements)
{
$bytesMedian = $measurements->median('wp->bytes');
return (object) [
'Metric' => WP_CLI::colorize('%bCache%n: Size'),
'Median' => is_null($bytesMedian) ? '' : size_format($bytesMedian, 1),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getPrefetches(Measurements $measurements)
{
$prefetchesMedian = $measurements->median('wp->prefetches');
return (object) [
'Metric' => WP_CLI::colorize('%bCache%n: Reads'),
'Median' => is_null($prefetchesMedian) ? '' : number_format($prefetchesMedian),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getStoreReads(Measurements $measurements)
{
$storeReadsMedian = $measurements->median('wp->storeReads');
return (object) [
'Metric' => WP_CLI::colorize('%bDatastore%n: Reads'),
'Median' => is_null($storeReadsMedian) ? '' : number_format($storeReadsMedian),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getStoreWrites(Measurements $measurements)
{
$storeWritesMedian = $measurements->median('wp->storeWrites');
return (object) [
'Metric' => WP_CLI::colorize('%bDatastore%n: Writes'),
'Median' => is_null($storeWritesMedian) ? '' : number_format($storeWritesMedian),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getStoreHits(Measurements $measurements)
{
$storeHitsMedian = $measurements->median('wp->storeHits');
return (object) [
'Metric' => WP_CLI::colorize('%bDatastore%n: Hits'),
'Median' => is_null($storeHitsMedian) ? '' : number_format($storeHitsMedian),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getStoreMisses(Measurements $measurements)
{
$storeMissesMedian = $measurements->median('wp->storeMisses');
return (object) [
'Metric' => WP_CLI::colorize('%bDatastore%n: Misses'),
'Median' => is_null($storeMissesMedian) ? '' : number_format($storeMissesMedian),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getSqlQueries(Measurements $measurements)
{
$sqlQueriesMedian = $measurements->median('wp->sqlQueries');
return (object) [
'Metric' => WP_CLI::colorize('%ySQL%n: Queries'),
'Median' => is_null($sqlQueriesMedian) ? '' : number_format($sqlQueriesMedian),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getMsTotal(Measurements $measurements)
{
$msTotalMedian = $measurements->median('wp->msTotal');
return (object) [
'Metric' => WP_CLI::colorize('%cTime%n: Request'),
'Median' => is_null($msTotalMedian) ? '' : number_format($msTotalMedian, 2) . ' ms',
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getMsCache(Measurements $measurements)
{
$msCacheMedian = $measurements->median('wp->msCache');
return (object) [
'Metric' => WP_CLI::colorize('%cTime%n: Cache'),
'Median' => is_null($msCacheMedian) ? '' : number_format($msCacheMedian, 2) . ' ms',
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getMsCacheAvg(Measurements $measurements)
{
$msCacheAvg = $measurements->median('wp->msCacheAvg');
return (object) [
'Metric' => WP_CLI::colorize('%cTime%n: Commands'),
'Median' => is_null($msCacheAvg) ? '' : number_format($msCacheAvg, 4) . ' ms',
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getMsCacheRatio(Measurements $measurements)
{
$msCacheRatioMedian = $measurements->median('wp->msCacheRatio');
return (object) [
'Metric' => WP_CLI::colorize('%cTime%n: Cache ratio'),
'Median' => is_null($msCacheRatioMedian) ? '' : number_format($msCacheRatioMedian, 2) . '%',
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisHits(Measurements $measurements)
{
$hits = $measurements->median('redis->hits');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Hits'),
'Median' => is_null($hits) ? '' : number_format($hits),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisMisses(Measurements $measurements)
{
$misses = $measurements->median('redis->misses');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Misses'),
'Median' => is_null($misses) ? '' : number_format($misses),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisHitRatio(Measurements $measurements)
{
$hitRatioMedian = $measurements->median('redis->hitRatio');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Hit ratio'),
'Median' => is_null($hitRatioMedian) ? '' : number_format($hitRatioMedian, 1) . '%',
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisOpsPerSec(Measurements $measurements)
{
$opsPerSec = $measurements->latest('redis->opsPerSec');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Operations'),
'Median' => is_null($opsPerSec) ? '' : number_format($opsPerSec) . ' ops/s',
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisEvictedKeys(Measurements $measurements)
{
$evictedKeys = $measurements->latest('redis->evictedKeys');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Evicted keys'),
'Median' => is_null($evictedKeys) ? '' : number_format($evictedKeys),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisUsedMemory(Measurements $measurements)
{
$usedMemory = $measurements->latest('redis->usedMemory');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Used memory'),
'Median' => is_null($usedMemory) ? '' : number_format($usedMemory),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisUsedMemoryRss(Measurements $measurements)
{
$usedMemoryRss = $measurements->latest('redis->usedMemoryRss');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Used memory RSS'),
'Median' => is_null($usedMemoryRss) ? '' : number_format($usedMemoryRss),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisMemoryFragmentationRatio(Measurements $measurements)
{
$memoryFragmentationRatio = $measurements->latest('redis->memoryFragmentationRatio');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Memory Frag. Ratio'),
'Median' => is_null($memoryFragmentationRatio) ? '' : number_format($memoryFragmentationRatio, 1) . '%',
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisConnectedClients(Measurements $measurements)
{
$connectedClients = $measurements->latest('redis->connectedClients');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Connected clients'),
'Median' => is_null($connectedClients) ? '' : number_format($connectedClients),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisTrackingClients(Measurements $measurements)
{
$trackingClients = $measurements->latest('redis->trackingClients');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Tracking clients'),
'Median' => is_null($trackingClients) ? '' : number_format($trackingClients),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisRejectedConnections(Measurements $measurements)
{
$rejectedConnections = $measurements->latest('redis->rejectedConnections');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Rejected connections'),
'Median' => is_null($rejectedConnections) ? '' : number_format($rejectedConnections),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRedisKeys(Measurements $measurements)
{
$keys = $measurements->latest('redis->keys');
return (object) [
'Metric' => WP_CLI::colorize('%rRedis%n: Keys'),
'Median' => is_null($keys) ? '' : number_format($keys),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRelayHits(Measurements $measurements)
{
$hits = $this->usingRelay
? $measurements->latest('relay->hits')
: null;
return (object) [
'Metric' => WP_CLI::colorize('%pRelay%n: Hits'),
'Median' => is_null($hits) ? '' : number_format($hits),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRelayMisses(Measurements $measurements)
{
$misses = $this->usingRelay
? $measurements->latest('relay->misses')
: null;
return (object) [
'Metric' => WP_CLI::colorize('%pRelay%n: Misses'),
'Median' => is_null($misses) ? '' : number_format($misses),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRelayKeys(Measurements $measurements)
{
$keys = $measurements->latest('relay->keys');
return (object) [
'Metric' => WP_CLI::colorize('%pRelay%n: Keys'),
'Median' => is_null($keys) ? '' : number_format($keys),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRelayMemoryUsed(Measurements $measurements)
{
$memoryUsed = $this->usingRelay
? $measurements->latest('relay->memoryUsed')
: null;
return (object) [
'Metric' => WP_CLI::colorize('%pRelay%n: Memory used'),
'Median' => is_null($memoryUsed) ? '' : size_format($memoryUsed),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRelayMemoryTotal(Measurements $measurements)
{
$memoryTotal = $this->usingRelay
? $measurements->latest('relay->memoryTotal')
: null;
return (object) [
'Metric' => WP_CLI::colorize('%pRelay%n: Memory total'),
'Median' => is_null($memoryTotal) ? '' : size_format($memoryTotal),
];
}
/**
* @param \RedisCachePro\Metrics\Measurements $measurements
* @return object
*/
protected function getRelayMemoryHuman(Measurements $measurements)
{
$memoryHuman = null;
if ($this->usingRelay) {
$memoryTotal = $measurements->latest('relay->memoryTotal');
$memoryUsed = $measurements->latest('relay->memoryUsed');
if ($memoryUsed && $memoryTotal) {
$memoryHuman = sprintf(
'%s / %s',
size_format($memoryUsed),
size_format($memoryTotal)
);
}
}
return (object) [
'Metric' => WP_CLI::colorize('%pRelay%n: Memory'),
'Median' => is_null($memoryHuman) ? '' : $memoryHuman,
];
}
}