Browse Source

Initial commit

pull/5/merge
Kai Kretschmann 4 years ago
commit
17360970da
18 changed files with 760 additions and 0 deletions
  1. 6
    0
      .htaccess
  2. 0
    0
      css/index.html
  3. 29
    0
      css/lggr.css
  4. 61
    0
      do.php
  5. 27
    0
      doc/db.sql
  6. BIN
      img/logo.png
  7. 1
    0
      inc/.htaccess
  8. 21
    0
      inc/config_class.php
  9. 0
    0
      inc/index.html
  10. 188
    0
      inc/lggr_class.php
  11. 70
    0
      inc/lggrstate_class.php
  12. 269
    0
      index.php
  13. 0
    0
      js/index.html
  14. 30
    0
      js/lggr.js
  15. 1
    0
      tpl/.htaccess
  16. 16
    0
      tpl/foot.inc.php
  17. 20
    0
      tpl/head.inc.php
  18. 21
    0
      tpl/paginate.inc.php

+ 6
- 0
.htaccess View File

@@ -0,0 +1,6 @@
Options -indexes

AuthType Basic
AuthName "Restricted Area"
AuthUserFile /var/www/webuser
Require valid-user

+ 0
- 0
css/index.html View File


+ 29
- 0
css/lggr.css View File

@@ -0,0 +1,29 @@
body > div {
margin-top: 3em;
}

.navbar-brand img {
height: 25px;
}

.datarow div {
white-space: nowrap;
overflow: hidden;
}

.datarow.even {
background-color: #e0e0e0;
}
.datarow.odd {
background-color: #c0c0c0;
}

.datarow .newlog-msg {
cursor: zoom-in;
}

p.debugfooter {
float: right;
color: #999999;
font-size: 75%;
}

+ 61
- 0
do.php View File

@@ -0,0 +1,61 @@
<?php

require 'inc/lggr_class.php';
require 'inc/lggrstate_class.php';

session_start();

if(!isset($_GET['a'])) {
header('Location: index.php');
exit;
} // if

if(isset($_SESSION[LggrState::SESSIONNAME])) {
$state = $_SESSION[LggrState::SESSIONNAME];
} else {
$state = new LggrState();
} // if


switch($_GET['a']) {

case 'reset':
$state = new LggrState();
break;

case 'search':
$state = new LggrState();
$state->setSearch($_POST['q']);
break;

case 'host':
$state->setHost($_GET['host']);
$state->setPage(0);
break;

case 'level':
$state->setLevel($_GET['level']);
$state->setPage(0);
break;

case 'range':
$i = intval($_GET['range']);
$state->setRange($i);
$state->setPage(0);
break;
case 'paginate':
if(isset($_GET['page'])) {
$i = intval($_GET['page']);
if($i<0) $i=0;

$page = $i;
$state->setPage($page);
} // if
break;

} // switch

$_SESSION[LggrState::SESSIONNAME] = $state;

header('Location: index.php');

+ 27
- 0
doc/db.sql View File

@@ -0,0 +1,27 @@
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- Exportiere Struktur von Tabelle lggrdev.newlogs
CREATE TABLE IF NOT EXISTS `newlogs` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`date` datetime NOT NULL,
`facility` enum('kern','user','mail','daemon','auth','syslog','lpr','news','uucp','authpriv','ftp','cron','local0','local1','local2','local3','local4','local5','local6','local7') NOT NULL,
`level` enum('emerg','alert','crit','err','warning','notice','info','debug') NOT NULL,
`host` char(16) NOT NULL,
`program` varchar(50) NOT NULL,
`pid` int(10) unsigned NOT NULL,
`message` text NOT NULL,
PRIMARY KEY (`id`),
KEY `level` (`level`),
KEY `host` (`host`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='New logging table';
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `LastHour` AS select `logger`.`newlogs`.`id` AS `id`,`logger`.`newlogs`.`date` AS `date`,`logger`.`newlogs`.`facility` AS `facility`,`logger`.`newlogs`.`level` AS `level`,`logger`.`newlogs`.`host` AS `host`,`logger`.`newlogs`.`program` AS `program`,`logger`.`newlogs`.`pid` AS `pid`,`logger`.`newlogs`.`message` AS `message` from `logger`.`newlogs` where (`logger`.`newlogs`.`date` >= (now() - interval 1 hour));
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `Today` AS select `logger`.`newlogs`.`id` AS `id`,`logger`.`newlogs`.`date` AS `date`,`logger`.`newlogs`.`facility` AS `facility`,`logger`.`newlogs`.`level` AS `level`,`logger`.`newlogs`.`host` AS `host`,`logger`.`newlogs`.`program` AS `program`,`logger`.`newlogs`.`pid` AS `pid`,`logger`.`newlogs`.`message` AS `message` from `logger`.`newlogs` where (cast(now() as date) = cast(`logger`.`newlogs`.`date` as date));
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `Week` AS select `logger`.`newlogs`.`id` AS `id`,`logger`.`newlogs`.`date` AS `date`,`logger`.`newlogs`.`facility` AS `facility`,`logger`.`newlogs`.`level` AS `level`,`logger`.`newlogs`.`host` AS `host`,`logger`.`newlogs`.`program` AS `program`,`logger`.`newlogs`.`pid` AS `pid`,`logger`.`newlogs`.`message` AS `message` from `logger`.`newlogs` where (`logger`.`newlogs`.`date` >= (now() - interval 168 hour));
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

BIN
img/logo.png View File


+ 1
- 0
inc/.htaccess View File

@@ -0,0 +1 @@
deny from all

+ 21
- 0
inc/config_class.php View File

@@ -0,0 +1,21 @@
<?php

class Config {

const DBUSER = 'lggr';
const DBPWD = 'lggr';
const DBNAME = 'lggrdev';

public function getDbUser() {
return self::DBUSER;
}

public function getDbPwd() {
return self::DBPWD;
}

public function getDbName() {
return self::DBNAME;
}

} // class

+ 0
- 0
inc/index.html View File


+ 188
- 0
inc/lggr_class.php View File

@@ -0,0 +1,188 @@
<?php

require_once 'config_class.php';

class Lggr {

private $config=null;
private $db=null;
private $state=null;

function __construct(LggrState $state) {
$this->config = new Config();
$this->state = $state;
$this->db = new mysqli('localhost', $this->config->getDbUSer(), $this->config->getDbPwd(), $this->config->getDbName());

$this->checkSecurity();
} // constructor

function __destruct() {
if(null != $this->db) {
$this->db->close();
} // if
} // destructor

private function checkSecurity() {
if(!isset($_SERVER['REMOTE_USER'])) {
throw new Exception('You must enable basic authentication');
} // if
} // function

private function getViewName() {
switch($this->state->getRange()) {
case 1: return 'LastHour'; break;
case 24: return 'Today'; break;
case 168: return 'Week'; break;
default: return 'Today'; break;
}
}

function getLevels() {
$v = $this->getViewName();
$a = array();
$sql = "
SELECT level, COUNT(*) AS c FROM $v
GROUP BY level
";

$res = $this->db->query($sql);
if(false === $res) {
throw new Exception($this->db->error);
} // if
while($row = $res->fetch_object()) {
$a[] = $row;
} // while
$res->close();

$sum = 0;
foreach($a as $level) {
$sum += $level->c;
} // foreach
foreach($a as $level) {
$f = $level->c / $sum * 100;
$level->f = round($f, 2);
} // foreach

return $a;
} // function

function getServers() {
$v = $this->getViewName();
$a = array();
$sql = "
SELECT host, COUNT(*) AS c FROM $v
GROUP BY host
ORDER BY c DESC
";

$res = $this->db->query($sql);
if(false === $res) {
throw new Exception($this->db->error);
} // if
while($row = $res->fetch_object()) {
$a[] = $row;
} // while
$res->close();

$sum = 0;
foreach($a as $host) {
$sum += $host->c;
} // foreach
foreach($a as $host) {
$f = $host->c / $sum * 100;
$host->f = round($f, 2);
} // foreach

return $a;
} // function

function getLatest($from=0, $count=100) {
$v = $this->getViewName();
$sql = "
SELECT * FROM $v
ORDER BY `date` DESC
LIMIT $from,$count";

return $this->sendResult($sql);
} // function

function getFiltered($host=null, $level=null, $from=0, $count=100) {
$v = $this->getViewName();

$sql = "SELECT * FROM $v";

$aWhere = array();
if(null != $host) {
$sTmp = $this->db->escape_string($host);
$aWhere[] = "host='$sTmp'";
} // if
if(null != $level) {
$sTmp = $this->db->escape_string($level);
$aWhere[] = "level='$sTmp'";
} // if

if(count($aWhere) > 0) {
$sql .= " WHERE " . implode(' AND ', $aWhere);
} // if

$sql .= " ORDER BY `date` DESC LIMIT $from,$count";

return $this->sendResult($sql);
} // function

function getByHost($host, $from=0, $count=100) {
$v = $this->getViewName();
$sTmp = $this->db->escape_string($host);

$sql = "
SELECT * FROM $v
WHERE host='$sTmp'
ORDER BY `date` DESC
LIMIT $from,$count";

return $this->sendResult($sql);
} // function

function getByLevel($level, $from=0, $count=100) {
$v = $this->getViewName();
$sTmp = $this->db->escape_string($level);

$sql = "
SELECT * FROM $v
WHERE level='$sTmp'
ORDER BY `date` DESC
LIMIT $from,$count";

return $this->sendResult($sql);
} // function

function getText($q, $from=0, $count=100) {
$v = $this->getViewName();
$sTmp = $this->db->escape_string($q);

$sql = "
SELECT * FROM $v
WHERE message LIKE '%{$sTmp}%'
ORDER BY `date` DESC
LIMIT $from,$count";

return $this->sendResult($sql);

} // function

private function sendResult($sql) {
$a = array();

$res = $this->db->query($sql);
if(false === $res) {
throw new Exception($this->db->error);
} // if
while($row = $res->fetch_object()) {
$a[] = $row;
} // while

$res->close();
return $a;
} // function

} // class

+ 70
- 0
inc/lggrstate_class.php View File

@@ -0,0 +1,70 @@
<?php

class LggrState {

const SESSIONNAME = 'LggrState';

private $bSearch=false;
private $sSearch=null;
private $iPage=0;
private $sHost=null;
private $sLevel=null;
private $iRange=24; // default 24h = today, sort of

function __construct() {
$this->iPage=0;
$this->bSearch=false;
$this->sSearch=null;
$this->sHost=null;
$this->sLevel=null;
$this->iRange=24;
} // constructor

public function setSearch($s) {
if(null != $s) {
$this->bSearch = true;
$this->sSearch = $s;
}
}
public function isSearch() {
return $this->bSearch;
}
public function getSearch() {
return $this->sSearch;
}

public function setPage($i) {
$this->iPage = $i;
}
public function getPage() {
return $this->iPage;
}

public function setHost($s) {
$this->sHost = $s;
}
public function getHost() {
return $this->sHost;
}
public function isHost() {
return null != $this->sHost;
}

public function setLevel($s) {
$this->sLevel = $s;
}
public function getLevel() {
return $this->sLevel;
}
public function isLevel() {
return null != $this->sLevel;
}

public function setRange($i) {
$this->iRange = $i;
}
public function getRange() {
return $this->iRange;
}

} // class

+ 269
- 0
index.php View File

@@ -0,0 +1,269 @@
<?php


require_once 'inc/lggrstate_class.php';
require_once 'inc/lggr_class.php';
require 'tpl/head.inc.php';

session_start();

if(isset($_SESSION[LggrState::SESSIONNAME])) {
$state = $_SESSION[LggrState::SESSIONNAME];
} else {
$state = new LggrState();
} // if

$l = null;
try {
$l = new Lggr($state);

$aLevels = $l->getLevels();
$aServers = $l->getServers();
} catch(Exception $e) {
echo '<div class="container"><div class="alert alert-danger" role="alert">' . $e->getMessage() . '</div></div>';

require 'tpl/foot.inc.php';

exit;
}

$aRanges = array(
'1' => 'This hour',
'24' => 'Today',
'168' => 'Week'
);

$page = $state->getPage();

try {
if($state->isSearch()) {

$aEvents = $l->getText($state->getSearch(), $page*100, 100);
$searchvalue = htmlentities($state->getSearch());
$isSearch=true;
$sFilter = 'Full text search result <strong>' . $searchvalue . '</strong>';

} elseif($state->isHost() || $state->isLevel()) {

$host = $state->getHost();
$level = $state->getLevel();

$aEvents = $l->getFiltered($host, $level, $page*100, 100);
$searchvalue='';
$isSearch=false;
$sFilter='';
if($state->isHost())
$sFilter .= 'Filter by server <strong>' . htmlentities($state->getHost()) . '</strong>';
if($state->isLevel())
$sFilter .= 'Filter by level <strong>' . htmlentities($state->getLevel()) . '</strong>';

} else {

$sFilter = null;

$aEvents = $l->getLatest($page*100, 100);
$searchvalue='';
$isSearch=false;

} // if search
} catch(Exception $e) {
echo '<div class="container"><div class="alert alert-danger" role="alert">' . $e->getMessage() . '</div></div>';

require 'tpl/foot.inc.php';

exit;
}
?>


<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="./do.php?a=reset"><img src="/img/logo.png" alt="Lggr.io" /></a>
</div>
<div style="height: 1px;" aria-expanded="false" id="navbar" class="navbar-collapse collapse">
<form method="post" action="./do.php?a=search" class="navbar-form navbar-right">
<div class="form-group">
<input name="q" placeholder="Search in messages" class="form-control" type="text" value="<?= $searchvalue ?>">
</div>
<button type="submit" class="btn btn-success">Search</button>
</form>
</div><!--/.navbar-collapse -->
</div>
</nav>

<div class="container">
<div class="row">
<div class="col-md-4">
<h2><span class="glyphicon glyphicon-tasks" aria-hidden="true"></span> Levels</h2>
<div class="progress">
<?php
$aLevelCount = array();
foreach($aLevels as $level) {
$aLevelCount[$level->level] = $level->c;
switch($level->level) {
case 'err':
$label='progress-bar-danger';
break;
case 'notice':
$label='progress-bar-warning';
break;
case 'info':
$label='progress-bar-success';
break;
default: $label='';
} // switch

echo <<<EOL
<div class="progress-bar $label" style="width: {$level->f}%" title="{$level->level} {$level->f}%">
<span class="sr-only">{$level->f}%</span>
</div>
EOL;
} // foreach
?>
</div>
<p>Distribution of selected event levels.</p>
<?php
if(isset($aLevelCount['err'])) {
echo '<button class="btn btn-primary" type="button">Error <span class="badge">' . $aLevelCount['err'] . '</span></button>';
}
?>
<?php
if(isset($aLevelCount['notice'])) {
echo '<button class="btn btn-primary" type="button">Notice <span class="badge">' . $aLevelCount['notice'] . '</span></button>';
}
?>
</div>

<div class="col-md-4">
<h2><span class="glyphicon glyphicon-align-left" aria-hidden="true"></span> Servers</h2>
<?php
foreach($aServers as $server) {
if($server->f < 5) continue;

echo <<<EOL
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="{$server->f}" aria-valuemin="0" aria-valuemax="100" style="width: {$server->f}%; min-width: 3em" title="{$server->host} {$server->f}%">
{$server->host} {$server->f}%
</div>
</div>
EOL;
} // foreach
?>
<p>Most reporting servers (5% or more).</p>
</div>

<div class="col-md-4">
<h2><span class="glyphicon glyphicon-filter" aria-hidden="true"></span> Filter</h2>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
Server
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<?php
foreach($aServers as $server) {
echo '<li role="presentation"><a role="menuitem" tabindex="-1" href="./do.php?a=host&host=' . urlencode($server->host) . '">' . $server->host . '</a></li>';
} // foreach
?>
</ul>
</div><!-- dropdown -->

<p><div class="btn-group" role="group" aria-label="level">
<?php
foreach($aLevels as $level) {
if($state->isLevel() && ($level->level == $state->getLevel())) {
echo '<button type="button" class="btn btn-primary newlog-level">' . $level->level . '</button>';
} else {
echo '<button type="button" class="btn btn-default newlog-level">' . $level->level . '</button>';
}
} // foreach
?>
</div></p>

<p><div class="btn-group" role="group" aria-label="range">
<?php
foreach($aRanges as $rangeValue => $rangeText) {
if($state->getRange() == $rangeValue) {
echo '<button type="button" class="btn btn-primary newlog-range" data-range="' . $rangeValue . '">' . $rangeText . '</button>';
} else {
echo '<button type="button" class="btn btn-default newlog-range" data-range="' . $rangeValue . '">' . $rangeText . '</button>';
}
} // foreach
?>
</div></p>
<p><a type="button" role="button" href="./do.php?a=reset" class="btn btn-default">
<span class="glyphicon glyphicon-refresh" aria-hidden="true"></span> Reset
</a></p>
</div>
</div>
</div> <!-- /container -->

<div class="container">
<?php

if(null != $sFilter) {
echo '<div class="alert alert-info" role="alert">' . $sFilter . '</div>';
} // if

if(0 == count($aEvents)) {
echo '<div class="alert alert-danger" role="alert">empty result</div>';
} // if

?>
</div>

<div class="container datablock">
<?php

include 'tpl/paginate.inc.php';

$i=0;
foreach($aEvents as $event) {
$i++;

if(0 == $i % 2) {
$rowclass='even';
} else {
$rowclass='odd';
} // if

switch($event->level) {
case 'err': $label = '<span class="label label-danger">Error</span>'; break;
case 'notice': $label='<span class="label label-warning">Notice</span>'; break;
case 'info': $label = '<span class="label label-info">Info</span>'; break;
default: $label = '<span class="label label-default">' . $event->level . '</span>';
} // switch

$host = htmlentities($event->host);
$program = htmlentities($event->program);
$msg = htmlentities($event->message);

echo <<<EOL
<div class="row datarow $rowclass" data-id="{$event->id}">
<div class="col-md-2 col-xs-6 newlog-date">{$event->date}</div>
<div class="col-md-1 col-xs-2">{$event->facility}</div>
<div class="col-md-1 col-xs-2">$label</div>
<div class="col-md-1 col-xs-2">$host</div>
<div class="col-md-2 col-xs-12">$program</div>
<div class="col-md-5 col-xs-12 newlog-msg" title="$msg"><tt>{$msg}</tt></div>
</div><!-- row -->
EOL;

} // foreach
?>
<div id="dialog" title="Details">I'm a dialog</div>

<?php
include 'tpl/paginate.inc.php';
?>

</div>

<?php require 'tpl/foot.inc.php' ?>

+ 0
- 0
js/index.html View File


+ 30
- 0
js/lggr.js View File

@@ -0,0 +1,30 @@
/* */

$(document).ready(function() {

$("#dialog").dialog({
autoOpen: false,
width: 500
});

$('div.datarow tt').on('click', function() {
var sTxt = $(this).html();
var sTitle = $(this).parent().parent().find('.newlog-date').text();

$('#dialog').html(sTxt).
dialog("option", "title", sTitle).
dialog("open");
});

$('button.newlog-level').on('click', function() {
var sLevel = $(this).text();
window.location.href = "./do.php?a=level&level=" + sLevel;
});

$('button.newlog-range').on('click', function() {
var iRange = $(this).attr('data-range');
window.location.href = "./do.php?a=range&range=" + iRange;
});


});

+ 1
- 0
tpl/.htaccess View File

@@ -0,0 +1 @@
deny from all

+ 16
- 0
tpl/foot.inc.php View File

@@ -0,0 +1,16 @@
<div class="container">
<hr>
<footer>
<p class="debugfooter">Session: <?= $_COOKIE['PHPSESSID'] ?> by <?= htmlentities($_SERVER['REMOTE_USER']) ?></p>
<p>&copy; <a href="http://lggr.io" target="_blank">lggr.io</a> 2015</p>
</footer>
</div> <!-- /container -->

<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="js/lggr.js"></script>
</body>
</html>

+ 20
- 0
tpl/head.inc.php View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Lggr.io</title>
<!-- Bootstrap -->
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<link href="css/lggr.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>

+ 21
- 0
tpl/paginate.inc.php View File

@@ -0,0 +1,21 @@
<nav>
<ul class="pagination">
<?php
if($page>0) {
echo '<li><a href="./do.php?a=paginate&page=' . ($page-1) . '" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>';
} else {
echo '<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>';
} // if

for($i=0; $i<9; $i++) {
if($page == $i) {
echo '<li class="active"><a href="./do.php?a=paginate&page=' . $i . '">' . ($i+1) . '</a></li>';
} else {
echo '<li><a href="./do.php?a=paginate&page=' . $i . '">' . ($i+1) . '</a></li>';
} // if
} // for i

echo '<li><a href="./do.php?a=paginate&page=' . ($page+1) . '" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>';
?>
</ul>
</nav>

Loading…
Cancel
Save
Social stuff:
Mastodon