o11y-8.x-1.x-dev/modules/o11y_metrics/src/Prometheus/Storage/DrupalCache.php
modules/o11y_metrics/src/Prometheus/Storage/DrupalCache.php
<?php
namespace Drupal\o11y_metrics\Prometheus\Storage;
use Drupal\pcb\Cache\PermanentDatabaseBackend;
use Drupal\pcb_memcache\Cache\PermanentMemcacheBackend;
use Drupal\pcb_redis\Cache\PermanentRedisBackend;
use Drupal\o11y_metrics\Prometheus\RelatesSourceToMetricsInterface;
use Drupal\o11y_metrics\BaseMetricsSourceInterface;
use Drupal\webprofiler\Cache\CacheBackendWrapper;
use Prometheus\Collector;
use Prometheus\Storage\InMemory;
use Drupal\Core\Installer\InstallerKernel;
/**
* Alternative promphp storage class based on drupal cache.
*/
class DrupalCache extends InMemory implements RelatesSourceToMetricsInterface {
/**
* The underlying cache backend.
*
* @var \Drupal\pcb\Cache\PermanentDatabaseBackend|\Drupal\pcb_memcache\Cache\PermanentMemcacheBackend|\Drupal\pcb_redis\Cache\PermanentRedisBackend
*/
protected $cacheBackend;
/**
* Constructor.
*/
public function __construct($cacheBackend) {
if ($cacheBackend instanceof CacheBackendWrapper) {
$cacheBackend = $cacheBackend->getWrapped();
}
$backendIsPermanent = ($cacheBackend instanceof PermanentDatabaseBackend)
|| ($cacheBackend instanceof PermanentMemcacheBackend)
|| ($cacheBackend instanceof PermanentRedisBackend);
if (!$backendIsPermanent && !InstallerKernel::installationAttempted()) {
throw new \RuntimeException(<<<EOD
Please configure the drupal prometheusio_bin cache bin to use either
- cache.backend.permanent_database
- cache.backend.permanent_redis
- cache.backend.permanent_memcache
EOD);
}
$this->cacheBackend = $cacheBackend;
}
/**
* {@inheritdoc}
*/
public function collect(): array {
foreach (['counters', 'gauges', 'histograms'] as $type) {
$this->{$type} = $this->cacheBackend->get('metrics:' . $type)->data ?? [];
}
return parent::collect();
}
/**
* {@inheritdoc}
*/
public function updateHistogram(array $data): void {
$this->commonUpdateMetric('histograms', __FUNCTION__, $data);
}
/**
* {@inheritdoc}
*/
public function updateGauge(array $data): void {
$this->commonUpdateMetric('gauges', __FUNCTION__, $data);
}
/**
* {@inheritdoc}
*/
public function updateCounter(array $data): void {
$this->commonUpdateMetric('counters', __FUNCTION__, $data);
}
/**
* Common metrics function.
*/
protected function commonUpdateMetric(string $classFieldName, string $method, array $data) {
$this->{$classFieldName} = $this->cacheBackend->get('metrics:' . $classFieldName)->data ?? [];
parent::$method($data);
$this->cacheBackend->set('metrics:' . $classFieldName, $this->{$classFieldName});
}
/**
* {@inheritdoc}
*/
public function wipeStorage(): void {
$this->cacheBackend->deleteAllPermanent();
parent::wipeStorage();
}
/**
* {@inheritdoc}
*/
public function associateSourceToMetric(
BaseMetricsSourceInterface $metricsSource,
Collector $metric
) {
$metrictype = $metric->getType();
$metricname = $metric->getName();
$metricsSourceId = $metricsSource::getMetricsSourceId();
$cid_association = 'source_metrics_associations:' . $metricsSourceId;
$associations = $this->cacheBackend->get($cid_association)->data ?? [];
$mappingMetricTypeClassField = [
'counter' => 'counters',
'histogram' => 'histograms',
'gauge' => 'gauges',
];
$metakey = $this->metaKey(['type' => $metrictype, 'name' => $metricname]);
$associations[$mappingMetricTypeClassField[$metrictype]][$metakey] = TRUE;
$this->cacheBackend->set($cid_association, $associations);
}
/**
* {@inheritdoc}
*/
public function removeMetricsOfSource(string $metricsSourceId) {
$cid_association = 'source_metrics_associations:' . $metricsSourceId;
$associations = $this->cacheBackend->get($cid_association)->data ?? [];
$classFieldNames = array_keys($associations);
foreach ($classFieldNames as $classFieldName) {
$cid = 'metrics:' . $classFieldName;
$cached = $this->cacheBackend->get($cid)->data ?? [];
foreach (array_keys($associations[$classFieldName]) as $metakey) {
unset($cached[$metakey]);
}
$this->cacheBackend->set($cid, $cached);
}
$this->cacheBackend->delete($cid_association);
}
/**
* {@inheritdoc}
*/
public function hasMetricsOfSource(string $metricsSourceId) {
$cid_association = 'source_metrics_associations:' . $metricsSourceId;
$associations = $this->cacheBackend->get($cid_association)->data ?? [];
return !empty($associations);
}
}
