commit
16a026194b
|
@ -28,7 +28,7 @@
|
|||
*/
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
# namespace Icinga\Application\Controllers;
|
||||
// namespace Icinga\Application\Controllers;
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Application\Icinga;
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
// @codingStandardsIgnoreStart
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/**
|
||||
* This file is part of Icinga Web 2.
|
||||
*
|
||||
* Icinga Web 2 - Head for multiple monitoring backends.
|
||||
* Copyright (C) 2013 Icinga Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* @copyright 2013 Icinga Development Team <info@icinga.org>
|
||||
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
||||
* @author Icinga Development Team <info@icinga.org>
|
||||
*
|
||||
*/
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
use Icinga\Module\Monitoring\Controller;
|
||||
use Icinga\Web\Hook;
|
||||
use Icinga\Application\Config as IcingaConfig;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
|
||||
/**
|
||||
* Class ListController
|
||||
*
|
||||
* Application wide controller for various listing actions
|
||||
*/
|
||||
class ListController extends Controller
|
||||
{
|
||||
/**
|
||||
* Add title tab
|
||||
*
|
||||
* @param string $action
|
||||
*/
|
||||
protected function addTitleTab($action)
|
||||
{
|
||||
$this->getTabs()->add($action, array(
|
||||
'title' => ucfirst($action),
|
||||
'url' => Url::fromPath(
|
||||
'list/'
|
||||
. str_replace(' ', '', $action)
|
||||
)
|
||||
))->activate($action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the application log
|
||||
*/
|
||||
public function applicationlogAction()
|
||||
{
|
||||
$this->addTitleTab('application log');
|
||||
$config_ini = IcingaConfig::app()->toArray();
|
||||
if (!in_array('logging', $config_ini) || (
|
||||
in_array('type', $config_ini['logging']) &&
|
||||
$config_ini['logging']['type'] === 'stream' &&
|
||||
in_array('target', $config_ini['logging']) &&
|
||||
file_exists($config_ini['logging']['target'])
|
||||
)
|
||||
) {
|
||||
$config = ResourceFactory::getResourceConfig('logfile');
|
||||
$resource = ResourceFactory::createResource($config);
|
||||
$this->view->logData = $resource->select()->order('DESC')->paginate();
|
||||
} else {
|
||||
$this->view->logData = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// @codingStandardsIgnoreEnd
|
|
@ -0,0 +1,24 @@
|
|||
<div class="controls">
|
||||
<?= $this->tabs->render($this) ?>
|
||||
<div style="margin-top: 1em"></div>
|
||||
<?= $this->logData ?>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<table class="action">
|
||||
<tbody>
|
||||
<?php foreach ($this->logData as $value): ?>
|
||||
<?php $datetime = new Datetime($value->datetime); ?>
|
||||
<tr class="state">
|
||||
<td style="width: 6em; text-align: center">
|
||||
<?= $this->escape($datetime->format('d.m. H:i')) ?><br />
|
||||
<?= $this->escape($value->loglevel) ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= $this->escape($value->message) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
|
@ -49,5 +49,3 @@ configPath = "@icingaweb_config_path@/preferences"
|
|||
; Use database storage to save preferences in either a MySQL or PostgreSQL database
|
||||
;type = db
|
||||
;resource = icingaweb-mysql
|
||||
|
||||
|
||||
|
|
|
@ -18,8 +18,12 @@ title = "Configuration"
|
|||
url = "config"
|
||||
priority = 300
|
||||
|
||||
[System.ApplicationLog]
|
||||
title = "Application log"
|
||||
url = "list/applicationlog"
|
||||
priority = 400
|
||||
|
||||
[Logout]
|
||||
url = "authentication/logout"
|
||||
icon = img/icons/logout.png
|
||||
priority = 300
|
||||
|
||||
|
|
|
@ -47,3 +47,9 @@ port = @ldap_port@
|
|||
root_dn = "@ldap_rootdn@"
|
||||
bind_dn = "@ldap_binddn@"
|
||||
bind_pw = @ldap_bindpass@
|
||||
|
||||
[logfile]
|
||||
type = file
|
||||
filename = "/vagrant/var/log/icingaweb.log"
|
||||
fields = "/^(?<datetime>[0-9]{4}(-[0-9]{2}){2}T[0-9]{2}(:[0-9]{2}){2}(\\+[0-9]{2}:[0-9]{2})?) (?<loglevel>[A-Za-z]+)( \([0-9]+\))?: (?<message>.*)$/"
|
||||
; format: PCRE
|
||||
|
|
|
@ -56,8 +56,7 @@ class Datasource implements DatasourceInterface
|
|||
|
||||
public function fetchAll(Query $query)
|
||||
{
|
||||
$result = $this->getResult($query);
|
||||
return $result;
|
||||
return $this->getResult($query);
|
||||
}
|
||||
|
||||
public function count(Query $query)
|
||||
|
|
|
@ -37,6 +37,7 @@ use Icinga\Data\Db\Connection as DbConnection;
|
|||
use Icinga\Protocol\Livestatus\Connection as LivestatusConnection;
|
||||
use Icinga\Protocol\Statusdat\Reader as StatusdatReader;
|
||||
use Icinga\Protocol\Ldap\Connection as LdapConnection;
|
||||
use Icinga\Protocol\File\Reader as FileReader;
|
||||
|
||||
class ResourceFactory implements ConfigAwareFactory
|
||||
{
|
||||
|
@ -133,6 +134,9 @@ class ResourceFactory implements ConfigAwareFactory
|
|||
case 'livestatus':
|
||||
$resource = new LivestatusConnection($config->socket);
|
||||
break;
|
||||
case 'file':
|
||||
$resource = new FileReader($config);
|
||||
break;
|
||||
default:
|
||||
throw new ConfigurationError('Unsupported resource type "' . $config->type . '"');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\File;
|
||||
|
||||
use Icinga\Data\BaseQuery;
|
||||
|
||||
/**
|
||||
* Class Query
|
||||
*
|
||||
* Query for Datasource Icinga\Protocol\File\Reader
|
||||
*
|
||||
* @package Icinga\Protocol\File
|
||||
*/
|
||||
class Query extends BaseQuery
|
||||
{
|
||||
/**
|
||||
* Sort direction
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $sortDir;
|
||||
|
||||
/**
|
||||
* Filters to apply on result
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $filters = array();
|
||||
|
||||
/**
|
||||
* Nothing to do here
|
||||
*/
|
||||
public function applyFilter()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Sort query result chronological
|
||||
*
|
||||
* @param string $dir Sort direction, 'ASC' or 'DESC' (default)
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
public function order($dir)
|
||||
{
|
||||
$this->sortDir = ($dir === null || strtoupper(trim($dir)) === 'DESC') ? self::SORT_DESC : self::SORT_ASC;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if sorting descending, false otherwise
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function sortDesc()
|
||||
{
|
||||
return $this->sortDir === self::SORT_DESC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an mandatory filter expression to be applied on this query
|
||||
*
|
||||
* @param string $expression the filter expression to be applied
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
public function andWhere($expression)
|
||||
{
|
||||
$this->filters[] = $expression;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filters currently applied on this query
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
return $this->filters;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,284 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\File;
|
||||
|
||||
use Icinga\Data\DatasourceInterface;
|
||||
|
||||
/**
|
||||
* Class Reader
|
||||
*
|
||||
* Read file line by line
|
||||
*
|
||||
* @package Icinga\Protocol\File
|
||||
*/
|
||||
class Reader implements DatasourceInterface
|
||||
{
|
||||
/**
|
||||
* Name of the file to read
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $filename;
|
||||
|
||||
/**
|
||||
* Configuration for this Datasource
|
||||
*
|
||||
* @var \Zend_Config
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @param \Zend_Config $config
|
||||
*/
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->filename = $config->filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a Query object
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
public function select()
|
||||
{
|
||||
return new Query($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch result as an array of objects
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAll(Query $query)
|
||||
{
|
||||
$all = array();
|
||||
foreach ($this->fetchPairs($query) as $index => $value) {
|
||||
$all[$index] = new \stdClass();
|
||||
foreach ($value as $key => $value_2) {
|
||||
$all[$index]->{$key} = $value_2;
|
||||
}
|
||||
}
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch first result row
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function fetchRow(Query $query)
|
||||
{
|
||||
$all = $this->fetchAll($query);
|
||||
if (isset($all[0])) {
|
||||
return $all[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch first result column
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchColumn(Query $query)
|
||||
{
|
||||
$column = array();
|
||||
foreach ($this->fetchPairs($query) as $value) {
|
||||
foreach ($value as $value_2) {
|
||||
$column[] = $value_2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch first column value from first result row
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function fetchOne(Query $query)
|
||||
{
|
||||
$pairs = $this->fetchPairs($query);
|
||||
if (isset($pairs[0])) {
|
||||
foreach ($pairs[0] as $value) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch result as a key/value pair array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchPairs(Query $query)
|
||||
{
|
||||
return $this->read($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* If given $line matches the $query's PCRE pattern and contains all the strings in the $query's filters array,
|
||||
* return an associative array of the matches of the PCRE pattern.
|
||||
* Otherwise, return false.
|
||||
* If preg_match returns false, it failed parsing the PCRE pattern.
|
||||
* In that case, throw an exception.
|
||||
*
|
||||
* @param string $line
|
||||
* @param Query $query
|
||||
*
|
||||
* @return array|bool
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function validateLine($line, Query $query)
|
||||
{
|
||||
$data = array();
|
||||
$PCRE_result = @preg_match($this->config->fields, $line, $data);
|
||||
if ($PCRE_result === false) {
|
||||
throw new \Exception('Failed parsing regular expression!');
|
||||
} else if ($PCRE_result === 1) {
|
||||
foreach ($query->getFilters() as $filter) {
|
||||
if (strpos($line, $filter) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach ($data as $key => $value) {
|
||||
if (is_int($key)) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip and read as many lines as needed according to given $query.
|
||||
*
|
||||
* @param Query $query
|
||||
*
|
||||
* @return array result
|
||||
*/
|
||||
public function read(Query $query)
|
||||
{
|
||||
$skip_lines = $query->getOffset();
|
||||
$read_lines = $query->getLimit();
|
||||
if ($skip_lines === null) {
|
||||
$skip_lines = 0;
|
||||
}
|
||||
return $this->{$query->sortDesc() ? 'readFromEnd' : 'readFromStart'}($skip_lines, $read_lines, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Backend for $this->read
|
||||
* Direction: LIFO
|
||||
*/
|
||||
public function readFromEnd($skip_lines, $read_lines, Query $query)
|
||||
{
|
||||
$PHP_EOL_len = strlen(PHP_EOL);
|
||||
$lines = array();
|
||||
$s = '';
|
||||
$f = fopen($this->filename, 'rb');
|
||||
fseek($f, 0, SEEK_END);
|
||||
$pos = ftell($f);
|
||||
while ($read_lines === null || count($lines) < $read_lines) {
|
||||
fseek($f, --$pos);
|
||||
$c = fgetc($f);
|
||||
if ($c === false || $pos < 0) {
|
||||
$l = $this->validateLine($s, $query);
|
||||
if (!($l === false || $skip_lines)) {
|
||||
$lines[] = $l;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$s = $c . $s;
|
||||
if (strpos($s, PHP_EOL) === 0) {
|
||||
$l = $this->validateLine((string)substr($s, $PHP_EOL_len), $query);
|
||||
if ($l !== false) {
|
||||
if ($skip_lines) {
|
||||
$skip_lines--;
|
||||
} else {
|
||||
$lines[] = $l;
|
||||
}
|
||||
}
|
||||
$s = '';
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backend for $this->read
|
||||
* Direction: FIFO
|
||||
*/
|
||||
public function readFromStart($skip_lines, $read_lines, Query $query)
|
||||
{
|
||||
$PHP_EOL_len = strlen(PHP_EOL);
|
||||
$lines = array();
|
||||
$s = '';
|
||||
$f = fopen($this->filename, 'rb');
|
||||
while ($read_lines === null || count($lines) < $read_lines) {
|
||||
$c = fgetc($f);
|
||||
if ($c === false) {
|
||||
$l = $this->validateLine($s, $query);
|
||||
if (!($l === false || $skip_lines)) {
|
||||
$lines[] = $l;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$s .= $c;
|
||||
if (strpos($s, PHP_EOL) !== false) {
|
||||
$l = $this->validateLine((string)substr($s, 0, strlen($s) - $PHP_EOL_len), $query);
|
||||
if ($l !== false) {
|
||||
if ($skip_lines) {
|
||||
$skip_lines--;
|
||||
} else {
|
||||
$lines[] = $l;
|
||||
}
|
||||
}
|
||||
$s = '';
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of available valid lines.
|
||||
*
|
||||
* @param Query $query
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count(Query $query) {
|
||||
$PHP_EOL_len = strlen(PHP_EOL);
|
||||
$lines = 0;
|
||||
$s = '';
|
||||
$f = fopen($this->filename, 'rb');
|
||||
fseek($f, 0, SEEK_END);
|
||||
$pos = ftell($f);
|
||||
while (true) {
|
||||
fseek($f, --$pos);
|
||||
$c = fgetc($f);
|
||||
if ($c === false || $pos < 0) {
|
||||
if ($this->validateLine($s, $query) !== false) {
|
||||
$lines++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$s = $c . $s;
|
||||
if (strpos($s, PHP_EOL) === 0) {
|
||||
if ($this->validateLine((string)substr($s, $PHP_EOL_len), $query) !== false) {
|
||||
$lines++;
|
||||
}
|
||||
$s = '';
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue