Initial commit
This commit is contained in:
commit
3d50432ff4
BIN
banner.png
Normal file
BIN
banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
61
data/config.php.example
Executable file
61
data/config.php.example
Executable file
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
## Set this if you do not have a default timezone set for PHP or if the time
|
||||||
|
## is incorrect. See https://www.php.net/manual/en/timezones.php
|
||||||
|
#date_default_timezone_set('America/New_York');
|
||||||
|
|
||||||
|
## If you have troubles with incorrect file paths, you should change this
|
||||||
|
## value to your webroot.
|
||||||
|
#$ROOT = '/var/www/status';
|
||||||
|
$ROOT = $_SERVER['DOCUMENT_ROOT']?:getcwd();
|
||||||
|
|
||||||
|
## Page Head values.
|
||||||
|
$CONFIG['site_name'] = 'Shakespeare';
|
||||||
|
$CONFIG['page_name'] = 'Status';
|
||||||
|
$CONFIG['site_description'] = 'The Official Status Page of Shakespeare';
|
||||||
|
$CONFIG['site_message'] = 'Am I online?';
|
||||||
|
|
||||||
|
## SQL database
|
||||||
|
## Refer to https://www.php.net/manual/en/pdo.construct.php
|
||||||
|
$CONFIG['db_host'] = 'sqlite:'.$ROOT.'/data/status.db';
|
||||||
|
## If using sqlite, you do not need these.
|
||||||
|
$CONFIG['db_username'] = null;
|
||||||
|
$CONFIG['db_password'] = null;
|
||||||
|
|
||||||
|
## Maximum amount of slices to show per service on page.
|
||||||
|
$CONFIG['max_slices'] = 48;
|
||||||
|
|
||||||
|
## Formatting for timestamp when displayed on page.
|
||||||
|
$CONFIG['timestamp_format'] = 'H:i';
|
||||||
|
|
||||||
|
## SERVICES
|
||||||
|
## This array holds all the services to be checked on run.
|
||||||
|
$CONFIG['services'] = array(
|
||||||
|
## This is an example service.
|
||||||
|
#'plays'=>array(
|
||||||
|
## This will be the name of the service as displayed on the status page.
|
||||||
|
#'name'=>'Web Server',
|
||||||
|
|
||||||
|
## This will be the message displayed under the collapsable title.
|
||||||
|
#'message'=>'To be, or not to be.',
|
||||||
|
|
||||||
|
## The pid file of the service to check. If 'process' is also defined,
|
||||||
|
## this will override its check. Make sure the runner has permissions
|
||||||
|
## to read the file.
|
||||||
|
#'pidfile'=>'/run/nginx.pid',
|
||||||
|
|
||||||
|
## Icon to display alongside the service name. Path is relative to page.
|
||||||
|
## You can also leave this blank for no icon.
|
||||||
|
#'icon'=>'http.png',
|
||||||
|
|
||||||
|
## Name of the process to query. This will search using pgrep.
|
||||||
|
#'process'=>'nginx',
|
||||||
|
|
||||||
|
## Hostname of the server to ping. This and 'ports' may be omitted if
|
||||||
|
## you do not want to ping it.
|
||||||
|
#'hostname'=>'shakespear.lit',
|
||||||
|
|
||||||
|
## Array of ports to ping. If more than one port, the displayed ping will be averaged. Requires 'hostname' to function properly.
|
||||||
|
#'ports'=>array(80,443)
|
||||||
|
#)
|
||||||
|
);
|
||||||
|
?>
|
136
data/update.php
Executable file
136
data/update.php
Executable file
|
@ -0,0 +1,136 @@
|
||||||
|
<?php
|
||||||
|
$CONFIG = array(); $services = array();
|
||||||
|
include(($_SERVER['DOCUMENT_ROOT']?:getcwd()).'/data/config.php');
|
||||||
|
|
||||||
|
$SQL = new PDO($CONFIG['db_host'], $CONFIG['db_username'], $CONFIG['db_password']);
|
||||||
|
if ($SQL->errorCode() && $SQL->errorCode() !== '00000') {
|
||||||
|
die($SQL->errorCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
$SQL->query('CREATE TABLE IF NOT EXISTS service_status(service TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, ping INTEGER, status INTEGER, PRIMARY KEY(service, timestamp))');
|
||||||
|
|
||||||
|
foreach($CONFIG['services'] as $id=>$data) {
|
||||||
|
$services[$id] = array(
|
||||||
|
'name'=>$data['name'],
|
||||||
|
'message'=>$data['message']
|
||||||
|
);
|
||||||
|
if (isset($data['icon'])) $services[$id]['icon'] = $data['icon'];
|
||||||
|
$timestamp = date('Y-m-d H:i:s');
|
||||||
|
// Ping is in ms. Status is 0 if okay, +1 for each unreachable, and -1 if offline completely.
|
||||||
|
$ping = -1; $status = 0;
|
||||||
|
// Check for ports (with ping)
|
||||||
|
if (isset($data['ports'])) {
|
||||||
|
$pings = array(); $i = 0;
|
||||||
|
foreach ($data['ports'] as $port) {
|
||||||
|
$starttime = microtime(true);
|
||||||
|
if ($fp = fsockopen($data['hostname'],$port,$errno,$errstr,15)) {
|
||||||
|
$stoptime = microtime(true);
|
||||||
|
$newping = ($stoptime - $starttime) * 1000;
|
||||||
|
$pings[$i++] = $newping;
|
||||||
|
} else $status++;
|
||||||
|
}
|
||||||
|
if ($i == 1)
|
||||||
|
$ping = round($pings[0], 2);
|
||||||
|
else if ($i > 0 && ($ping_sum = array_sum($pings)) > 0)
|
||||||
|
$ping = round($ping_sum / $i, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for PID (status)
|
||||||
|
if (isset($data['pidfile'])) {
|
||||||
|
if (!posix_getpgid(file_get_contents($data['pidfile'])))
|
||||||
|
$status = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for process (status)
|
||||||
|
if (isset($data['process']) && !isset($data['pidfile'])) {
|
||||||
|
$otp; $rtn;
|
||||||
|
exec('pgrep -fl "'.$data['process'].'"', $otp, $rtn);
|
||||||
|
if ($rtn!=0) $status = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($stmt = $SQL->prepare('INSERT INTO service_status(service, timestamp, ping, status) VALUES (?, ?, ?, ?)')) {
|
||||||
|
$stmt->bindParam(1, $id);
|
||||||
|
$stmt->bindParam(2, $timestamp);
|
||||||
|
$stmt->bindParam(3, $ping);
|
||||||
|
$stmt->bindParam(4, $status);
|
||||||
|
$stmt->execute();
|
||||||
|
$stmt->closeCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($stmt = $SQL->prepare('SELECT timestamp,ping,status FROM service_status WHERE service = ? ORDER BY timestamp DESC LIMIT ?')) {
|
||||||
|
$stmt->bindParam(1, $id);
|
||||||
|
$stmt->bindParam(2, $CONFIG['max_slices']);
|
||||||
|
if ($stmt->execute()) {
|
||||||
|
$services[$id]['status'] = array();
|
||||||
|
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
array_push($services[$id]['status'], $row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$stmt->closeCursor();
|
||||||
|
}
|
||||||
|
$services[$id]['status'] = array_reverse($services[$id]['status']);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title><?=$CONFIG['page_name'];?></title>
|
||||||
|
<meta property='og:site_name' content='<?=$CONFIG['site_name'];?>'>
|
||||||
|
<meta property='og:image' content='favicon.png'>
|
||||||
|
<meta property='og:title' content='<?=$CONFIG['page_name'];?>'>
|
||||||
|
<meta property='og:description' content='<?=$CONFIG['site_description'];?>'>
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||||
|
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
|
||||||
|
<link rel='icon' href='favicon.png' type='image/png' sizes='64x64'>
|
||||||
|
<link rel='icon' href='favicon.ico' type='image/x-icon' sizes='64x64'>
|
||||||
|
<link rel='stylesheet' href='style.css'>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<center class='page'>
|
||||||
|
<div class='banner'><img src='banner.png'><br><h3>Status Page</h3><a><?=$CONFIG['site_message'];?></a></div>
|
||||||
|
<?php
|
||||||
|
foreach ($services as $service) {
|
||||||
|
echo '<table class=\'status\'>';
|
||||||
|
echo '<tr class=\'title\'><td colspan=\''.count($service['status']).'\'>';
|
||||||
|
if (!empty($service['message'])) {
|
||||||
|
echo '<details><summary><b>';
|
||||||
|
if (!empty($service['icon']))
|
||||||
|
echo '<img src=\''.$service['icon'].'\' height=\'16\'> ';
|
||||||
|
echo $service['name'].'</b></summary>'.$service['message'].'</details>';
|
||||||
|
} else {
|
||||||
|
if (!empty($service['icon']))
|
||||||
|
echo '<img src=\''.$service['icon'].'\' height=\'16\'> ';
|
||||||
|
echo '<b>'.$service['name'].'</b>';
|
||||||
|
}
|
||||||
|
echo '</td></tr>';
|
||||||
|
echo '<tr>';
|
||||||
|
foreach ($service['status'] as $slice) {
|
||||||
|
$cell_status; $bgclrstyle = '';
|
||||||
|
$_time = date($CONFIG['timestamp_format'], strtotime($slice['timestamp']));
|
||||||
|
$_ping = $slice['ping'].'ms';
|
||||||
|
|
||||||
|
if ($slice['status'] > 0 || ($slice['status'] == -1 && $slice['ping'] > 0)) {
|
||||||
|
$cell_status = 'partial';
|
||||||
|
$bgclrstyle = sprintf("#%02x%02x%02x", 255, 128, 0);
|
||||||
|
} else if ($slice['status'] == -1) {
|
||||||
|
$cell_status = 'offline';
|
||||||
|
$bgclrstyle = sprintf("#%02x%02x%02x", 255, 0, 0);
|
||||||
|
} else {
|
||||||
|
$cell_status = 'ok';
|
||||||
|
$bgclrstyle = sprintf(
|
||||||
|
"#%02x%02x%02x",
|
||||||
|
$slice['ping']!=-1?max(0, min(255, round($slice['ping'])*2)):0,
|
||||||
|
max(0, min(255, 128+(round($slice['ping'])/2))),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<td class=\''.$cell_status.'\' bgcolor=\''.$bgclrstyle.'\' value=\''.$_ping."\n".strtoupper($cell_status).' - '.$_time.'\'></td>';
|
||||||
|
}
|
||||||
|
echo '</tr></table>'."\n";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<hr>
|
||||||
|
</center>
|
||||||
|
</body>
|
||||||
|
</html>
|
28
style.css
Executable file
28
style.css
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
body {
|
||||||
|
background: #d3d3d3;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > center > * {
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
details {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
details > summary {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
table { width: 100%; }
|
||||||
|
table.status { margin: 8px 0; }
|
||||||
|
table.status tr:not(.title) td { height: 16px; }
|
||||||
|
table.status tr:not(.title) td:hover:after {
|
||||||
|
content: attr(value);
|
||||||
|
position: absolute;
|
||||||
|
background-color: rgba(0,0,0,0.75);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
padding: 2px 4px;
|
||||||
|
margin: -58px -8px;
|
||||||
|
white-space: pre;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user