Merge pull request #3502 from Icinga/feature/plugin-output-hook

Introduce monitoring/PluginOutputHook
This commit is contained in:
Eric Lippmann 2018-07-18 14:18:27 +02:00 committed by GitHub
commit 658cc72141
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 259 additions and 8 deletions

View File

@ -100,7 +100,8 @@ class HostController extends MonitoredObjectController
'service_active_checks_enabled',
'service_passive_checks_enabled',
'current_check_attempt' => 'service_current_check_attempt',
'max_check_attempts' => 'service_max_check_attempts'
'max_check_attempts' => 'service_max_check_attempts',
'service_check_command'
));
$this->applyRestriction('monitoring/filter/objects', $query);
$this->view->services = $query->where('host_name', $this->object->getName());

View File

@ -76,7 +76,8 @@ class ListController extends Controller
'host_last_state_change' => $stateChangeColumn,
'host_notifications_enabled',
'host_active_checks_enabled',
'host_passive_checks_enabled'
'host_passive_checks_enabled',
'host_check_command'
), $this->addColumns()));
$this->applyRestriction('monitoring/filter/objects', $hosts);
@ -156,7 +157,8 @@ class ListController extends Controller
'service_severity',
'service_notifications_enabled',
'service_active_checks_enabled',
'service_passive_checks_enabled'
'service_passive_checks_enabled',
'service_check_command'
), $this->addColumns()));
$this->applyRestriction('monitoring/filter/objects', $services);

View File

@ -76,19 +76,31 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
'<table style="font-size: 0.75em"'
);
/** @var \Icinga\Module\Monitoring\Web\Helper\PluginOutputHookRenderer */
protected $hookRenderer;
public function __construct()
{
$this->hookRenderer = (new \Icinga\Module\Monitoring\Web\Helper\PluginOutputHookRenderer())->registerHooks();
}
/**
* Render plugin output
*
* @param string $output
* @param bool $raw
* @param string $command Check command
*
* @return string
*/
public function pluginOutput($output, $raw = false)
public function pluginOutput($output, $raw = false, $command = null)
{
if (empty($output)) {
return '';
}
if ($command !== null) {
$output = $this->hookRenderer->render($command, $output, ! $raw);
}
$output = preg_replace('~<br[^>]*>~', "\n", $output);
if (preg_match('~<[^>]*["/\'][^>]*>~', $output)) {
// HTML

View File

@ -82,7 +82,7 @@ if (! $this->compact): ?>
<?php endif ?>
<span class="state-icons"><?= $this->hostFlags($host) ?></span>
</div>
<p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true) ?></p>
<p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true, $host->host_check_command) ?></p>
</td>
<?php foreach($this->addColumns as $col): ?>
<td><?= $this->escape($host->$col) ?></td>

View File

@ -86,7 +86,7 @@ if (! $this->compact): ?>
<div class="overview-performance-data">
<?= $this->perfdata($service->service_perfdata, true, 5) ?>
</div>
<p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($service->service_output, 10000), true) ?></p>
<p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($service->service_output, 10000), true, $service->service_check_command) ?></p>
</div>
</td>
<?php foreach($this->addColumns as $col): ?>

View File

@ -1,3 +1,3 @@
<h2><?= $this->translate('Plugin Output') ?></h2>
<?= $this->pluginOutput($object->output) ?>
<?= $this->pluginOutput($object->long_output) ?>
<?= $this->pluginOutput($object->output, false, $object->check_command) ?>
<?= $this->pluginOutput($object->long_output, false, $object->check_command) ?>

View File

@ -74,3 +74,88 @@ class Simple extends DetailviewExtensionHook
### How it looks <a id="monitoring-module-hooks-detailviewextension-how-it-looks"></a>
![Screenshot](img/hooks-detailviewextension-01.png)
## Plugin Output Hook <a id="monitoring-module-hooks-pluginoutput"></a>
The Plugin Output Hook allows you to rewrite the plugin output based on check commands. You have to implement the
following methods:
* `getCommands()`
* and `render()`
With `getCommands()` you specify for which commands the provided hook is responsible for. You may return a single
command as string or a list of commands as array. If you want your hook to be responsible for every command, you have to
specify the `*`.
In `render()` you rewrite the plugin output based on check commands. The parameter `$command` specifies the check
command of the host or service and `$output` specifies the plugin output. The parameter `$detail` tells you
whether the output is requested from the detail area of the host or service.
Do not use complex logic for rewriting plugin output in list views because of the performance impact!
You have to return the rewritten plugin output as string. It is also possible to return a HTML string here.
Please refer to `\Icinga\Module\Monitoring\Web\Helper\PluginOutputPurifier` for a list of allowed tags.
Please also have a look at the following examples.
**Example hook which is responsible for disk checks:**
```php
<?php
namespace Icinga\Module\Example\ProvidedHook\Monitoring;
use Icinga\Module\Monitoring\Hook\PluginOutputHook;
class PluginOutput extends PluginOutputHook
{
public function getCommands()
{
return ['disk'];
}
public function render($command, $output, $detail)
{
if (! $detail) {
// Don't rewrite plugin output in list views
return $output;
}
return implode('<br>', explode(';', $output));
}
}
```
**Example hook which is responsible for disk and procs checks:**
```php
<?php
namespace Icinga\Module\Example\ProvidedHook\Monitoring;
use Icinga\Module\Monitoring\Hook\PluginOutputHook;
class PluginOutput extends PluginOutputHook
{
public function getCommands()
{
return ['disk', 'procs'];
}
public function render($command, $output, $detail)
{
switch ($command) {
case 'disk':
if ($detail) {
// Only rewrite plugin output in the detail area
$output = implode('<br>', explode(';', $output));
}
break;
case 'procs':
$output = preg_replace('/(\d)+/', '<b>$1</b>', $output);
break;
}
return $output;
}
}
```

View File

@ -0,0 +1,46 @@
<?php
/* Icinga Web 2 | (c) 2018 Icinga Development Team | GPLv2+ */
namespace Icinga\Module\Monitoring\Hook;
/**
* Base class for plugin output hooks
*
* The Plugin Output Hook allows you to rewrite the plugin output based on check commands.
* You have to implement the following methods:
* * {@link getCommands()}
* * and {@link render()}
*/
abstract class PluginOutputHook
{
/**
* Get the command or list of commands the hook is responsible for
*
* With this method you specify for which commands the provided hook is responsible for. You may return a single
* command as string or a list of commands as array.
* If you want your hook to be responsible for every command, you have to return the asterisk `'*'`.
*
* @return string|array
*/
abstract public function getCommands();
/**
* Render the given plugin output based on the specified check command
*
* With this method you rewrite the plugin output based on check commands. The parameter `$command` specifies the
* check command of the host or service and `$output` specifies the plugin output. The parameter `$detail` tells you
* whether the output is requested from the detail area of the host or service.
*
* Do not use complex logic for rewriting plugin output in list views because of the performance impact!
*
* You have to return the rewritten plugin output as string. It is also possible to return a HTML string here.
* Please refer to {@link \Icinga\Module\Monitoring\Web\Helper\PluginOutputPurifier} for a list of allowed tags.
*
* @param string $command Check command
* @param string $output Plugin output
* @param bool $detail Whether the output is requested from the detail area
*
* @return string Rewritten plugin output
*/
abstract public function render($command, $output, $detail);
}

View File

@ -0,0 +1,105 @@
<?php
/* Icinga Web 2 | (c) 2018 Icinga Development Team | GPLv2+ */
namespace Icinga\Module\Monitoring\Web\Helper;
use Icinga\Application\Logger;
use Icinga\Web\Hook;
/**
* Renderer for plugin output based on hooks
*/
class PluginOutputHookRenderer
{
/** @var array */
protected $commandMap = [];
/**
* Register PluginOutput hooks
*
* Map PluginOutput hooks to their responsible commands.
*
* @return $this
*/
public function registerHooks()
{
if (! Hook::has('monitoring/PluginOutput')) {
return $this;
}
foreach (Hook::all('monitoring/PluginOutput') as $hook) {
/** @var \Icinga\Module\Monitoring\Hook\PluginOutputHook $hook */
try {
$commands = $hook->getCommands();
} catch (\Exception $e) {
Logger::error(
'Failed to get applicable commands from hook "%s". An error occurred: %s',
get_class($hook),
$e
);
continue;
}
if (! is_array($commands)) {
$commands = [$commands];
}
foreach ($commands as $command) {
if (! isset($this->commandMap[$command])) {
$this->commandMap[$command] = [];
}
$this->commandMap[$command][] = $hook;
}
}
return $this;
}
protected function renderCommand($command, $output, $detail)
{
if (isset($this->commandMap[$command])) {
foreach ($this->commandMap[$command] as $hook) {
/** @var \Icinga\Module\Monitoring\Hook\PluginOutputHook $hook */
try {
$output = $hook->render($command, $output, $detail);
} catch (\Exception $e) {
Logger::error(
'Failed to render plugin output from hook "%s". An error occurred: %s',
get_class($hook),
$e
);
continue;
}
}
}
return $output;
}
/**
* Render the given plugin output based on the specified check command
*
* Traverse all hooks which are responsible for the specified check command and call their `render()` methods.
*
* @param string $command Check command
* @param string $output Plugin output
* @param bool $detail Whether the output is requested from the detail area
*
* @return string
*/
public function render($command, $output, $detail)
{
if (empty($this->commandMap)) {
return $output;
}
$output = $this->renderCommand('*', $output, $detail);
$output = $this->renderCommand($command, $output, $detail);
return $output;
}
}