icingaweb2/library/Icinga/Application/Hook/HealthHook.php

223 lines
4.7 KiB
PHP

<?php
/* Icinga Web 2 | (c) 2021 Icinga GmbH | GPLv2+ */
namespace Icinga\Application\Hook;
use Exception;
use Icinga\Application\Hook;
use Icinga\Application\Logger;
use Icinga\Data\DataArray\ArrayDatasource;
use Icinga\Exception\IcingaException;
use ipl\Web\Url;
use LogicException;
abstract class HealthHook
{
/** @var int */
const STATE_OK = 0;
/** @var int */
const STATE_WARNING = 1;
/** @var int */
const STATE_CRITICAL = 2;
/** @var int */
const STATE_UNKNOWN = 3;
/** @var int The overall state */
protected $state;
/** @var string Message describing the overall state */
protected $message;
/** @var array Available metrics */
protected $metrics;
/** @var Url Url to a graphical representation of the available metrics */
protected $url;
/**
* Get overall state
*
* @return int
*/
public function getState()
{
return $this->state;
}
/**
* Set overall state
*
* @param int $state
*
* @return $this
*/
public function setState($state)
{
$this->state = $state;
return $this;
}
/**
* Get the message describing the overall state
*
* @return string
*/
public function getMessage()
{
return $this->message;
}
/**
* Set the message describing the overall state
*
* @param string $message
*
* @return $this
*/
public function setMessage($message)
{
$this->message = $message;
return $this;
}
/**
* Get available metrics
*
* @return array
*/
public function getMetrics()
{
return $this->metrics;
}
/**
* Set available metrics
*
* @param array $metrics
*
* @return $this
*/
public function setMetrics(array $metrics)
{
$this->metrics = $metrics;
return $this;
}
/**
* Get the url to a graphical representation of the available metrics
*
* @return Url
*/
public function getUrl()
{
return $this->url;
}
/**
* Set the url to a graphical representation of the available metrics
*
* @param Url $url
*
* @return $this
*/
public function setUrl(Url $url)
{
$this->url = $url;
return $this;
}
/**
* Collect available health data from hooks
*
* @return ArrayDatasource
*/
final public static function collectHealthData()
{
$checks = [];
foreach (Hook::all('health') as $hook) {
/** @var self $hook */
try {
$hook->checkHealth();
$url = $hook->getUrl();
$state = $hook->getState();
$message = $hook->getMessage();
$metrics = $hook->getMetrics();
} catch (Exception $e) {
Logger::error('Failed to check health: %s', $e);
$state = self::STATE_UNKNOWN;
$message = IcingaException::describe($e);
$metrics = null;
$url = null;
}
$checks[] = (object) [
'module' => $hook->getModuleName(),
'name' => $hook->getName(),
'url' => $url ? $url->getAbsoluteUrl() : null,
'state' => $state,
'message' => $message,
'metrics' => (object) $metrics
];
}
return (new ArrayDatasource($checks))
->setKeyColumn('name');
}
/**
* Get the name of the hook
*
* Only used in API responses to differentiate it from other hooks of the same module.
*
* @return string
*/
public function getName()
{
$classPath = get_class($this);
$parts = explode('\\', $classPath);
$className = array_pop($parts);
if (substr($className, -4) === 'Hook') {
$className = substr($className, 1, -4);
}
return strtolower($className[0]) . substr($className, 1);
}
/**
* Get the name of the module providing this hook
*
* @return string
*
* @throws LogicException
*/
public function getModuleName()
{
$classPath = get_class($this);
if (substr($classPath, 0, 14) !== 'Icinga\\Module\\') {
throw new LogicException('Not a module hook');
}
$withoutPrefix = substr($classPath, 14);
return strtolower(substr($withoutPrefix, 0, strpos($withoutPrefix, '\\')));
}
/**
* Check health
*
* Implement this method and set the overall state, message, url and metrics.
*
* @return void
*/
abstract public function checkHealth();
}