Implement simple-to-use image URLs /graph/*

refs #46
This commit is contained in:
Alexander A. Klimov 2017-09-21 16:45:37 +02:00
parent 1f5d59a4ad
commit 53848ed5b7
3 changed files with 228 additions and 80 deletions

View file

@ -0,0 +1,117 @@
<?php
namespace Icinga\Module\Graphite\Controllers;
use Icinga\Exception\Http\HttpBadRequestException;
use Icinga\Exception\Http\HttpNotFoundException;
use Icinga\Module\Graphite\GraphiteQuery;
use Icinga\Module\Graphite\GraphTemplate;
use Icinga\Module\Graphite\Web\Widget\GraphsTrait;
use Icinga\Web\Controller;
use Icinga\Web\UrlParams;
class GraphController extends Controller
{
use GraphsTrait;
/**
* The URL parameters for graph sizing
*
* @var string[]
*/
protected $geometryParamsNames = ['start', 'end', 'width', 'height', 'legend'];
/**
* Whether we supply a service's graph
*
* @var bool
*/
protected $service = true;
/**
* The URL parameters for metrics filtering
*
* @var UrlParams
*/
protected $filterParams;
/**
* The URL parameters for graph sizing
*
* @var string[string]
*/
protected $geometryParams = [];
public function hostAction()
{
$this->service = false;
$this->supplyImage();
}
public function serviceAction()
{
$this->supplyImage();
}
/**
* Do all monitored object type independend actions
*/
protected function supplyImage()
{
$this->filterParams = clone $this->getRequest()->getUrl()->getParams();
foreach ($this->geometryParamsNames as $paramName) {
$this->geometryParams[$paramName] = $this->filterParams->shift($paramName);
}
$this->collectTemplates();
$this->collectGraphiteQueries();
$charts = [];
foreach ($this->graphiteQueries as $templateName => $graphiteQuery) {
/** @var GraphiteQuery $graphiteQuery */
$charts = array_merge($charts, $graphiteQuery->getImages($this->templates[$templateName]));
if (count($charts) > 1) {
throw new HttpBadRequestException('%s', $this->translate(
'Graphite Web yields more than one metric for the given filter.'
. ' Please specify a more precise filter.'
));
}
}
if (empty($charts)) {
throw new HttpNotFoundException('%s', $this->translate('No such graph'));
}
$image = $charts[0]
->setStart($this->geometryParams['start'])
->setUntil($this->geometryParams['end'])
->setWidth($this->geometryParams['width'])
->setHeight($this->geometryParams['height'])
->showLegend((bool) $this->geometryParams['legend'])
->fetchImage();
$this->_helper->layout()->disableLayout();
header('Content-Type: image/png');
header('Content-Disposition: inline; filename="graph.png"');
echo $image;
exit;
}
protected function includeTemplate(GraphTemplate $template)
{
return (strpos($template->getFilterString(), '$service') !== false) === $this->service;
}
protected function filterGraphiteQuery(GraphiteQuery $query)
{
foreach ($this->filterParams->toArray() as list($key, $value)) {
$query->where($key, $value);
}
return $query;
}
}

View file

@ -22,19 +22,7 @@ use Icinga\Web\Widget\AbstractWidget;
abstract class Graphs extends AbstractWidget
{
/**
* [$setName => $set]
*
* @var TemplateSet[string]
*/
protected static $templateSets;
/**
* [$setName => [$templateName => $template]]
*
* @var GraphTemplate[string][string]
*/
protected static $allTemplates = [];
use GraphsTrait;
/**
* Graph image width
@ -80,11 +68,6 @@ abstract class Graphs extends AbstractWidget
*/
protected $images;
/**
* @var GraphTemplate[string]
*/
protected $templates;
/**
* Factory, based on the given object
*
@ -185,77 +168,27 @@ abstract class Graphs extends AbstractWidget
return [$params->get($absolute['start'], '-1hours'), $params->get($absolute['end'])];
}
/**
* Initialize {@link templates}
*/
protected function collectTemplates()
{
if (static::$templateSets === null) {
static::$templateSets = (new TemplateStore())->loadTemplateSets();
}
foreach (static::$templateSets as $setname => $set) {
/** @var TemplateSet $set */
if (array_key_exists('icingaHost', $set->getBasePatterns())) {
if (! isset(static::$allTemplates[$setname])) {
static::$allTemplates[$setname] = $set->loadTemplates();
}
foreach (static::$allTemplates[$setname] as $templateName => $template) {
/** @var GraphTemplate $template */
if ($this->includeTemplate($template)) {
$this->templates[$templateName] = $template;
}
}
}
}
}
/**
* Initialize {@link images}
*/
protected function collectImages()
{
$graphiteWeb = new GraphiteWeb(GraphiteWebClient::getInstance());
foreach ($this->templates as $templateName => $template) {
/** @var GraphTemplate $template */
$this->collectGraphiteQueries();
$this->images[$templateName] = $this->filterGraphiteQuery(
$graphiteWeb->select()->from($template->getFilterString())
)
->getWrappedImageLinks(
$template,
TimeRangePickerTrait::copyAllRangeParameters(
(new UrlParams())
->set('template', $templateName)
->set('start', $this->start)
->set('width', $this->width)
->set('height', $this->height)
)
);
foreach ($this->graphiteQueries as $templateName => $graphiteQuery) {
$this->images[$templateName] = $graphiteQuery->getWrappedImageLinks(
$this->templates[$templateName],
TimeRangePickerTrait::copyAllRangeParameters(
(new UrlParams())
->set('template', $templateName)
->set('start', $this->start)
->set('width', $this->width)
->set('height', $this->height)
)
);
}
}
/**
* Add filters to the given query so that only specific graphs are shown
*
* @param GraphiteQuery $query
*
* @return GraphiteQuery The given query
*/
abstract protected function filterGraphiteQuery(GraphiteQuery $query);
/**
* Return whether to use the given template
*
* @param GraphTemplate $template
*
* @return bool
*/
abstract protected function includeTemplate(GraphTemplate $template);
/**
* Get {@link compact}
*

View file

@ -0,0 +1,98 @@
<?php
namespace Icinga\Module\Graphite\Web\Widget;
use Icinga\Module\Graphite\GraphiteQuery;
use Icinga\Module\Graphite\GraphiteWeb;
use Icinga\Module\Graphite\GraphiteWebClient;
use Icinga\Module\Graphite\GraphTemplate;
use Icinga\Module\Graphite\TemplateSet;
use Icinga\Module\Graphite\TemplateStore;
trait GraphsTrait
{
/**
* [$setName => $set]
*
* @var TemplateSet[string]
*/
protected static $templateSets;
/**
* [$setName => [$templateName => $template]]
*
* @var GraphTemplate[string][string]
*/
protected static $allTemplates = [];
/**
* @var GraphTemplate[string]
*/
protected $templates;
/**
* @var GraphiteQuery[string]
*/
protected $graphiteQueries;
/**
* Initialize {@link templates}
*/
protected function collectTemplates()
{
if (static::$templateSets === null) {
static::$templateSets = (new TemplateStore())->loadTemplateSets();
}
foreach (static::$templateSets as $setname => $set) {
/** @var TemplateSet $set */
if (array_key_exists('icingaHost', $set->getBasePatterns())) {
if (! isset(static::$allTemplates[$setname])) {
static::$allTemplates[$setname] = $set->loadTemplates();
}
foreach (static::$allTemplates[$setname] as $templateName => $template) {
/** @var GraphTemplate $template */
if ($this->includeTemplate($template)) {
$this->templates[$templateName] = $template;
}
}
}
}
}
/**
* Initialize {@link graphiteQueries}
*/
protected function collectGraphiteQueries()
{
$graphiteWeb = new GraphiteWeb(GraphiteWebClient::getInstance());
foreach ($this->templates as $templateName => $template) {
/** @var GraphTemplate $template */
$this->graphiteQueries[$templateName] = $this->filterGraphiteQuery(
$graphiteWeb->select()->from($template->getFilterString())
);
}
}
/**
* Return whether to use the given template
*
* @param GraphTemplate $template
*
* @return bool
*/
abstract protected function includeTemplate(GraphTemplate $template);
/**
* Add filters to the given query so that only specific graphs are shown
*
* @param GraphiteQuery $query
*
* @return GraphiteQuery The given query
*/
abstract protected function filterGraphiteQuery(GraphiteQuery $query);
}