monitoring-8.x-1.x-dev/modules/prometheus/src/Controller/MetricsController.php
modules/prometheus/src/Controller/MetricsController.php
<?php
namespace Drupal\monitoring_prometheus\Controller;
use Drupal\Core\Access\AccessResultAllowed;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Utility\Token;
use Drupal\monitoring\SensorRunner;
use PNX\Prometheus\Gauge;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\SerializerInterface;
/**
* A controller for exporting prometheus metrics.
*/
class MetricsController extends ControllerBase {
/**
* MetricsController constructor.
*/
public function __construct(
protected SerializerInterface $serializer,
protected SensorRunner $sensorRunner,
protected Token $token) {
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('monitoring_prometheus.serializer'),
$container->get('monitoring.sensor_runner'),
$container->get('token')
);
}
/**
* Handles metrics requests.
*/
public function metrics() {
if (!class_exists(Gauge::class)) {
throw new \Exception('Required dependency not found, run composer require previousnext/php-prometheus.');
}
$default_labels = [];
$labels_config = $this->config('monitoring_prometheus.settings')->get('custom_labels') ?? [];
foreach ($labels_config as $label_name => $label_value) {
$default_labels[$label_name] = $this->token->replace($label_value);
}
$results = $this->sensorRunner->runSensors();
$output = [];
$count_by_status = [];
foreach ($results as $result) {
$sensor_config = $result->getSensorConfig();
$count_by_status[$result->getStatus()] = ($count_by_status[$result->getStatus()] ?? 0) + 1;
$metric_type = $sensor_config->getPlugin()->getPluginDefinition()['metric_type'] ?? NULL;
if ($metric_type != 'gauge') {
continue;
}
$value_label = mb_strtolower($result->getSensorConfig()->getValueLabel() ?? 'No label');
$value_label = preg_replace('/[^a-z]+/', '', $value_label) ?: 'total';
$gauge = new Gauge('drupal_' . $result->getSensorId(), $value_label, $result->getSensorConfig()->label());
$gauge->set($result->getValue() ?: 0, $default_labels);
$output[] = $this->serializer->serialize($gauge, 'prometheus');
if (!empty($sensor_config->getPlugin()->getPluginDefinition()['report_execution_time'])) {
$gauge = new Gauge('drupal_' . $result->getSensorId(), 'execution_time_seconds', $result->getSensorConfig()->label());
$gauge->set($result->getExecutionTime() / 1000, $default_labels);
$output[] = $this->serializer->serialize($gauge, 'prometheus');
}
}
$gauge = new Gauge('drupal_sensors', 'total' , $this->t('Sensor count by status'));
$gauge->set(array_sum($count_by_status), $default_labels);
foreach ($count_by_status as $status => $count) {
$gauge->set($count, array_merge($default_labels, ['status' => $status]));
}
$output[] = $this->serializer->serialize($gauge, 'prometheus');
$response = new Response();
$response->setMaxAge(0);
$response->headers->set('Content-Type', 'text/plain; version=0.0.4');
$response->setContent(implode($output));
return $response;
}
/**
* Custom IP access check.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Drupal\Core\Access\AccessResultInterface
* If there is a list of allowed ips, check request client against it.
*/
public function ipAccess(Request $request): AccessResultInterface {
$allowed_ips = array_filter($this->config('monitoring_prometheus.settings')->get('allowed_ips'));
return AccessResultAllowed::allowedIf(empty($allowed_ips) || in_array($request->getClientIp(), $allowed_ips));
}
}
