3 namespace Drupal\memcache_admin\EventSubscriber;
5 use Drupal\Core\Render\Element\HtmlTag;
6 use Drupal\Core\Render\Markup;
7 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
8 use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
9 use Symfony\Component\HttpKernel\KernelEvents;
10 use Drupal\Component\Render\HtmlEscapedText;
11 use Drupal\Core\Render\HtmlResponse;
14 * Memcache Admin Subscriber.
16 class MemcacheAdminSubscriber implements EventSubscriberInterface {
21 public static function getSubscribedEvents() {
22 $events[KernelEvents::RESPONSE][] = ['displayStatistics'];
27 * Display statistics on page.
29 public function displayStatistics(FilterResponseEvent $event) {
30 $user = \Drupal::currentUser();
32 // Removed exclusion criteria, untested. Will likely need to add some of
34 // @codingStandardsIgnoreStart
35 // strstr($_SERVER['PHP_SELF'], '/update.php')
36 // substr($_GET['q'], 0, strlen('batch')) == 'batch'
37 // strstr($_GET['q'], 'autocomplete')
38 // substr($_GET['q'], 0, strlen('system/files')) == 'system/files'
39 // in_array($_GET['q'], ['upload/js', 'admin/content/node-settings/rebuild'])
40 // @codingStandardsIgnoreEnd
41 // @todo validate these checks
42 if ($user->id() == 0) {
43 // Suppress for the above criteria.
46 $response = $event->getResponse();
48 // Don't call theme() during shutdown if the registry has been rebuilt
49 // (such as when enabling/disabling modules on admin/build/modules) as
51 // Instead, simply exit without displaying admin statistics for this page
52 // load. See http://drupal.org/node/616282 for discussion.
53 // @todo make sure this is not still a requirement.
54 // @codingStandardsIgnoreStart
55 // if (!function_exists('theme_get_registry') || !theme_get_registry()) {
58 // @codingStandardsIgnoreEnd
59 // Try not to break non-HTML pages.
60 if ($response instanceof HTMLResponse) {
62 // This should only apply to page content.
63 if (stripos($response->headers->get('content-type'), 'text/html') !== FALSE) {
64 $show_stats = \Drupal::config('memcache_admin.settings')->get('show_memcache_statistics');
65 if ($show_stats && $user->hasPermission('access memcache statistics')) {
68 $memcache = \Drupal::service('memcache.factory')->get(NULL, TRUE);
69 $memcache_stats = $memcache->requestStats();
70 if (!empty($memcache_stats['ops'])) {
71 foreach ($memcache_stats['ops'] as $row => $stats) {
72 $memcache_stats['ops'][$row][0] = new HtmlEscapedText($stats[0]);
73 $memcache_stats['ops'][$row][1] = number_format($stats[1], 2);
74 $hits = number_format($this->statsPercent($stats[2], $stats[3]), 1);
75 $misses = number_format($this->statsPercent($stats[3], $stats[2]), 1);
76 $memcache_stats['ops'][$row][2] = number_format($stats[2]) . " ($hits%)";
77 $memcache_stats['ops'][$row][3] = number_format($stats[3]) . " ($misses%)";
88 '#rows' => $memcache_stats['ops'],
90 $output .= \Drupal::service('renderer')->renderRoot($build);
93 if (!empty($memcache_stats['all'])) {
104 foreach ($memcache_stats['all'] as $row => $stats) {
105 $build[$row]['ms'] = ['#plain_text' => $stats[0]];
106 $build[$row]['operation'] = ['#plain_text' => $stats[1]];
107 $build[$row]['bin'] = ['#plain_text' => $stats[2]];
108 $build[$row]['key'] = [
109 '#separator' => ' | ',
111 foreach (explode('\n', $stats[3]) as $akey) {
112 $build[$row]['key']['child'][]['#plain_text'] = $akey;
114 $build[$row]['status'] = ['#plain_text' => $stats[4]];
116 $output .= \Drupal::service('renderer')->renderRoot($build);
119 if (!empty($output)) {
120 $response->setContent($response->getContent() . '<div id="memcache-devel"><h2>' . t('Memcache statistics') . '</h2>' . $output . '</div>');
129 * Helper function. Calculate a percentage.
131 private function statsPercent($a, $b) {
139 return $a / ($a + $b) * 100;