cache_monitor-1.0.x-dev/src/Cache/TimingBackend.php

src/Cache/TimingBackend.php
<?php

namespace Drupal\cache_monitor\Cache;

use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\cache_monitor\Metrics\Aggregator;

/**
 * Measures time per cache operation and reports to Aggregator.
 */
final class TimingBackend implements CacheBackendInterface {

  /**
   * Request-level cached decision.
   *
   * @var bool|null
   */
  private static ?bool $cacheMonitorMetricsAllowed = null;

  /**
   * The decorated cache backend.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  private CacheBackendInterface $inner;

  /**
   * The name of the cache bin.
   *
   * @var string
   */
  private string $bin;

  private string $backend;

  /**
   * The metrics aggregator.
   *
   * @var \Drupal\cache_monitor\Metrics\Aggregator
   */
  private Aggregator $agg;



  /**
   * Constructs a new TimingBackend instance.
   *
   * @param \Drupal\Core\Cache\CacheBackendInterface $inner
   *   The decorated cache backend.
   * @param string $bin
   *   The name of the cache bin.
   * @param \Drupal\cache_monitor\Metrics\Aggregator $agg
   *   The metrics aggregator.
   */
  public function __construct(
    CacheBackendInterface $inner,
    string $bin,
    Aggregator $agg
  ) {
    $this->inner = $inner;
    $this->bin = $bin;
    $this->agg = $agg;
    $this->backend = get_class($inner);
  }

  /**
   * Determine if metrics collection is allowed.
   */
  private function metricsAllowed(): bool {
    if (self::$cacheMonitorMetricsAllowed !== null) {
      return self::$cacheMonitorMetricsAllowed;
    }
    try {
      $state = \Drupal::state();
      if (!$state->get('cache_monitor.metrics_enabled', false)) {
        return self::$cacheMonitorMetricsAllowed = false;
      }
      $paths = $state->get('cache_monitor.paths', []);
      if (!is_array($paths) || $paths === []) {
        return self::$cacheMonitorMetricsAllowed = true;
      }
      if (!\Drupal::hasService('path.current') || !\Drupal::hasService('path_alias.manager')) {
        return self::$cacheMonitorMetricsAllowed = false;
      }

      $current = \Drupal::service('path.current')->getPath() ?: '/';
      $currentNoSlash = ltrim($current, '/');
      $internal = \Drupal::service('path_alias.manager')->getPathByAlias($current);
      $internalNoSlash = ltrim($internal, '/');

      return self::$cacheMonitorMetricsAllowed = (
        in_array($currentNoSlash, $paths, true) ||
        in_array($internalNoSlash, $paths, true)
      );
    }
    catch (\Throwable $e) {
      return self::$cacheMonitorMetricsAllowed = false;
    }
  }

  /**
   * Times a callable and records the time taken.
   *
   * @param callable $fn
   *   The callable to time.
   * @param string $op
   *   The operation name.
   * @param int $count
   *   The count of items processed (for batch operations).
   *
   * @return mixed
   *   The result of the callable.
   */
  private function t(callable $fn, string $op, int $count = 1) {
    if (!$this->metricsAllowed()) {
      return $fn();
    }
    $t0 = hrtime(true);
    $res = $fn();
    $ms = (hrtime(true) - $t0) / 1e6;
    $this->agg->add($this->bin, $this->backend, $op, $count, $ms);
    return $res;
  }

  /**
   * {@inheritdoc}
   */
  public function get($cid, $allow_invalid = FALSE) {
    return $this->t(fn() => $this->inner->get($cid, $allow_invalid), 'get');
  }

  /**
   * {@inheritdoc}
   */
  public function getMultiple(&$cids, $allow_invalid = FALSE) {
    $n = is_array($cids) ? count($cids) : 0;
    return $this->t(fn() => $this->inner->getMultiple($cids, $allow_invalid), 'getMultiple', $n);
  }

  /**
   * {@inheritdoc}
   */
  public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANENT, array $tags = []) {
    return $this->t(fn() => $this->inner->set($cid, $data, $expire, $tags), 'set');
  }

  /**
   * {@inheritdoc}
   */
  public function setMultiple(array $items) {
    return $this->t(fn() => $this->inner->setMultiple($items), 'setMultiple', count($items));
  }

  /**
   * {@inheritdoc}
   */
  public function delete($cid) {
    return $this->t(fn() => $this->inner->delete($cid), 'delete');
  }

  /**
   * {@inheritdoc}
   */
  public function deleteMultiple(array $cids) {
    return $this->t(fn() => $this->inner->deleteMultiple($cids), 'deleteMultiple', count($cids));
  }

  /**
   * {@inheritdoc}
   */
  public function invalidateAll() {
    return $this->t(fn() => $this->inner->invalidateAll(), 'invalidateAll');
  }

  /**
   * {@inheritdoc}
   */
  public function deleteAll() {
    return $this->t(fn() => $this->inner->deleteAll(), 'deleteAll');
  }

  /**
   * {@inheritdoc}
   */
  public function invalidate($cid) {
    return $this->t(fn() => $this->inner->invalidate($cid), 'invalidate');
  }

  /**
   * {@inheritdoc}
   */
  public function invalidateMultiple(array $cids) {
    return $this->t(fn() => $this->inner->invalidateMultiple($cids), 'invalidateMultiple', count($cids));
  }

  /**
   * {@inheritdoc}
   */
  public function invalidateTags(array $tags) {
    return $this->t(fn() => $this->inner->invalidateTags($tags), 'invalidateTags', count($tags));
  }

  /**
   * {@inheritdoc}
   */
  public function removeBin() {
    return $this->t(fn() => $this->inner->removeBin(), 'removeBin');
  }

  /**
   * {@inheritdoc}
   */
  public function garbageCollection() {
    return $this->t(fn() => $this->inner->garbageCollection(), 'garbageCollection');
  }
}

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

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