cache_monitor-1.0.x-dev/src/EventSubscriber/FlushSubscriber.php

src/EventSubscriber/FlushSubscriber.php
<?php

namespace Drupal\cache_monitor\EventSubscriber;

use Drupal\Core\Database\Database;
use Drupal\cache_monitor\Metrics\Aggregator;
use Drupal\cache_monitor\Storage\Storage;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\State\StateInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * On kernel terminate, flush aggregated metrics to storage.
 */
final class FlushSubscriber implements EventSubscriberInterface {

  /** @var \Drupal\cache_monitor\Metrics\Aggregator */
  private Aggregator $agg;
  /** @var \Drupal\cache_monitor\Storage\Storage */
  private Storage $storage;
  /** @var \Drupal\Core\Session\AccountInterface */
  private AccountInterface $currentUser;

  /** @var \Drupal\Core\State\StateInterface */
  private StateInterface $state;

  /**
   * Constructs a new FlushSubscriber instance.
   *
   * @param \Drupal\cache_monitor\Metrics\Aggregator $agg
   *   The metrics aggregator.
   * @param \Drupal\cache_monitor\Storage\Storage $storage
   *   The storage service.
   * @param \Drupal\Core\Session\AccountInterface $currentUser
   *   The current user.
   * @param \Drupal\Core\State\StateInterface $state
   *  The state service.
   */
  public function __construct(
    Aggregator $agg,
    Storage $storage,
    AccountInterface $currentUser,
    StateInterface $state
  ) {
    $this->agg = $agg;
    $this->storage = $storage;
    $this->currentUser = $currentUser;
    $this->state = $state;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    return [KernelEvents::TERMINATE => 'onTerminate'];
  }

  /**
   * Checks if the storage tables are ready.
   *
   * If not, we cannot save metrics (e.g. during install or update).
   */
  private function storageReady(): bool {
    try {
      $schema = Database::getConnection()->schema();
      return $schema->tableExists('cache_monitor_request') && $schema->tableExists('cache_monitor_metric');
    }
    catch (\Exception $e) {
      // DB not ready (installing, updating, broken connection).
      return false;
    }
  }

  /**
   * On kernel terminate, flush aggregated metrics to storage.
   *
   * @param \Symfony\Component\HttpKernel\Event\TerminateEvent $event
   *   The terminate event.
   */
  public function onTerminate(TerminateEvent $event): void {

    if (!$this->storageReady()) {
      $this->agg->drain(); // Cleanup, but skip saving.
      return;
    }

    $rows = $this->agg->drain();

    if (empty($rows)) {
      return; // Nothing to save.
    }

    $knownBins = array_keys(Cache::getBins());
    $observed  = array_unique(array_map(fn($r) => $r['bin'], $rows));
    $allBins   = array_values(array_unique(array_merge($knownBins, $observed)));
    sort($allBins);

    $req = $event->getRequest();

    try {
      $this->storage->save([
        'method'  => $req->getMethod(),
        'uri'     => $req->getRequestUri(),
        'uid'     => (int) $this->currentUser->id(),
        'ip'      => $req->getClientIp() ?: '',
        'context' => $req->attributes->get('_route') ?: NULL,
      ], $rows, $allBins);
    }
    catch (\Throwable $e) {
      // Never break the request; optionally log to watchdog.
      \Drupal::logger('cache_monitor_timing')->warning('Saving metrics failed: @m', ['@m' => $e->getMessage()]);
    }
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc