o11y-8.x-1.x-dev/modules/o11y_metrics/src/Bridge/PrometheusBridge.php

modules/o11y_metrics/src/Bridge/PrometheusBridge.php
<?php

namespace Drupal\o11y_metrics\Bridge;

use Drupal\o11y_metrics\Prometheus\CollectorRegistryForNonPlugins;
use Prometheus\CollectorRegistry;
use Prometheus\RenderTextFormat;
use Prometheus\Storage\InMemory;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Drupal\o11y_metrics\BaseMetricsSourceInterface;
use Drupal\o11y_metrics\Prometheus\Storage\DrupalCache;

/**
 * {@inheritdoc}
 */
class PrometheusBridge implements PrometheusBridgeInterface {

  use ContainerAwareTrait;

  /**
   * Stateful promphp collector registry.
   *
   * @var \Drupal\o11y_metrics\Prometheus\CollectorRegistryForNonPlugins
   */
  protected $collectorRegistryForNonPlugins;

  /**
   * Stateless promphp collector registry.
   *
   * @var \Prometheus\CollectorRegistry
   */
  protected CollectorRegistry $collectorRegistryForPlugins;

  /**
   * The site settings.
   *
   * @var \Drupal\Core\Site\Settings
   */
  protected $settings;

  /**
   * The promphp renderer.
   *
   * @var \Prometheus\RenderTextFormat
   */
  protected $renderer;

  /**
   * Default is drupal cache.
   */
  public function __construct(DrupalCache $drupalCache) {
    $this->collectorRegistryForNonPlugins = new CollectorRegistryForNonPlugins($drupalCache, FALSE);
    $this->collectorRegistryForPlugins = new CollectorRegistry(new InMemory(), FALSE);
    $this->renderer = new RenderTextFormat();
  }

  /**
   * {@inheritdoc}
   */
  public function render(): string {
    $metrics_with_storage = $this->renderer->render($this->collectorRegistryForNonPlugins->getMetricFamilySamples());
    // Now execute the plugin metrics and get their rendered result.
    // Plugins should call getCounter/getGauge/getHistogram without passing a
    // $metricsSource, i.e. using a collector registry that uses an InMemory
    // storage, i.e. a storage whose persistence does not outlive the request
    // lifetime.
    // Plugins are executed only during scraping of prometheus route (/metrics).
    // If plugins used a persistent storage then they could register say a
    // gauge like `drupal_config_status_sync{has_changes="0"} 1` at scrape t1
    // and `drupal_config_status_sync{has_changes="1"} 1` at scrape t2.
    // Except that at scrape 2 both lines would be outputted.
    /** @var \Drupal\o11y_metrics\MetricsCollectorManagerInterface $collector_manager */
    $collector_manager = $this->container->get('o11y_metrics.metrics_collector_manager');
    $collector_manager->executeMetricsPlugins();
    $metrics_without_storage = $this->renderer->render($this->collectorRegistryForPlugins->getMetricFamilySamples());
    return implode(PHP_EOL, array_filter(array_map('trim', [
      $metrics_with_storage,
      $metrics_without_storage,
    ])));
  }

  /**
   * {@inheritdoc}
   */
  public function getCounter(
    string $namespace,
    string $name,
    string $help,
    array $labels = [],
    BaseMetricsSourceInterface $metricsSource = NULL
  ) {
    $args = [$namespace, $name, $help, $labels];
    if ($metricsSource) {
      $metric = $this->collectorRegistryForNonPlugins->getOrRegisterCounter(...$args);
      $this->collectorRegistryForNonPlugins->associateSourceToMetric($metricsSource, $metric);
    }
    else {
      $metric = $this->collectorRegistryForPlugins->getOrRegisterCounter(...$args);
    }
    return $metric;
  }

  /**
   * {@inheritdoc}
   */
  public function getGauge(
    string $namespace,
    string $name,
    string $help,
    array $labels = [],
    BaseMetricsSourceInterface $metricsSource = NULL
  ) {
    $args = [$namespace, $name, $help, $labels];
    if ($metricsSource) {
      $metric = $this->collectorRegistryForNonPlugins->getOrRegisterGauge(...$args);
      $this->collectorRegistryForNonPlugins->associateSourceToMetric($metricsSource, $metric);
    }
    else {
      $metric = $this->collectorRegistryForPlugins->getOrRegisterGauge(...$args);
    }
    return $metric;
  }

  /**
   * {@inheritdoc}
   */
  public function getHistogram(
    string $namespace,
    string $name,
    string $help,
    array $labels = [],
    array $buckets = NULL,
    BaseMetricsSourceInterface $metricsSource = NULL
  ) {
    $args = [$namespace, $name, $help, $labels, $buckets];
    if ($metricsSource) {
      $metric = $this->collectorRegistryForNonPlugins->getOrRegisterHistogram(...$args);
      $this->collectorRegistryForNonPlugins->associateSourceToMetric($metricsSource, $metric);
    }
    else {
      $metric = $this->collectorRegistryForPlugins->getOrRegisterHistogram(...$args);
    }
    return $metric;
  }

  /**
   * {@inheritdoc}
   */
  public function getSummary(
    string $namespace,
    string $name,
    string $help,
    array $labels = [],
    int $maxAgeSeconds = 600,
    array $quantiles = NULL,
    BaseMetricsSourceInterface $metricsSource = NULL
  ) {
    $args = [$namespace, $name, $help, $labels, $maxAgeSeconds, $quantiles];
    if ($metricsSource) {
      $metric = $this->collectorRegistryForNonPlugins->getOrRegisterSummary(...$args);
      $this->collectorRegistryForNonPlugins->associateSourceToMetric($metricsSource, $metric);
    }
    else {
      $metric = $this->collectorRegistryForPlugins->getOrRegisterSummary(...$args);
    }
    return $metric;
  }

  /**
   * {@inheritdoc}
   */
  public function removeMetricsOfSource(string $metricsSourceClassName) {
    $sourceId = $this->getSourceIdFromMetricsSourceClassName($metricsSourceClassName);
    $this->collectorRegistryForNonPlugins->removeMetricsOfSource($sourceId);
  }

  /**
   * {@inheritdoc}
   */
  public function hasMetricsOfSource(string $metricsSourceClassName) {
    $sourceId = $this->getSourceIdFromMetricsSourceClassName($metricsSourceClassName);
    return $this->collectorRegistryForNonPlugins->hasMetricsOfSource($sourceId);
  }

  /**
   * {@inheritdoc}
   */
  public function wipeMetrics() {
    $this->collectorRegistryForNonPlugins->wipeStorage();
    $this->collectorRegistryForPlugins->wipeStorage();
  }

  /**
   * Utility function.
   */
  protected function getSourceIdFromMetricsSourceClassName(string $metricsSourceClassName) {
    $ifaces = class_implements($metricsSourceClassName);
    if (empty($ifaces[BaseMetricsSourceInterface::class])) {
      throw new \InvalidArgumentException('Parameter $metricsSourceClassName of ' . __METHOD__ . ' should implement interface ' . BaseMetricsSourceInterface::class);
    }
    return $metricsSourceClassName::getMetricsSourceId();
  }

}

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

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