172 lines
5.3 KiB
PHP
172 lines
5.3 KiB
PHP
<?php // phpcs:ignoreFile
|
|
|
|
require __DIR__ . '/../includes/db.php';
|
|
|
|
$appTimeZone = new DateTimeZone('America/Chicago');
|
|
$errorMessage = null;
|
|
$devices = [];
|
|
|
|
try {
|
|
$connection = controls_db_connect();
|
|
} catch (Throwable $exception) {
|
|
$connection = null;
|
|
$errorMessage = $exception->getMessage();
|
|
}
|
|
|
|
if ($connection instanceof mysqli) {
|
|
$sql = <<<SQL
|
|
SELECT d.id,
|
|
d.host,
|
|
d.label,
|
|
latest.status,
|
|
latest.latency_ms,
|
|
latest.checked_at
|
|
FROM monitoring_devices AS d
|
|
LEFT JOIN (
|
|
SELECT l1.device_id,
|
|
l1.status,
|
|
l1.latency_ms,
|
|
l1.checked_at
|
|
FROM monitoring_latency_log AS l1
|
|
INNER JOIN (
|
|
SELECT device_id, MAX(checked_at) AS max_checked
|
|
FROM monitoring_latency_log
|
|
GROUP BY device_id
|
|
) AS recent ON recent.device_id = l1.device_id AND recent.max_checked = l1.checked_at
|
|
) AS latest ON latest.device_id = d.id
|
|
WHERE d.is_active = 1
|
|
ORDER BY d.label;
|
|
SQL;
|
|
|
|
try {
|
|
$result = $connection->query($sql);
|
|
if ($result instanceof mysqli_result) {
|
|
while ($row = $result->fetch_assoc()) {
|
|
if (!empty($row['checked_at'])) {
|
|
$timestamp = DateTimeImmutable::createFromFormat(
|
|
'Y-m-d H:i:s',
|
|
$row['checked_at'],
|
|
new DateTimeZone('UTC')
|
|
);
|
|
if ($timestamp instanceof DateTimeImmutable) {
|
|
$timestamp = $timestamp->setTimezone($appTimeZone);
|
|
$row['checked_at_formatted'] = $timestamp->format('M j, Y g:i:s A T');
|
|
}
|
|
}
|
|
|
|
$devices[] = $row;
|
|
}
|
|
$result->free();
|
|
}
|
|
} catch (Throwable $exception) {
|
|
$errorMessage = $exception->getMessage();
|
|
} finally {
|
|
$connection->close();
|
|
}
|
|
}
|
|
|
|
ob_start();
|
|
?>
|
|
|
|
<header class="panel-header">
|
|
<h2>Device latency status</h2>
|
|
<p>Latest response times collected by the latency watcher service.</p>
|
|
</header>
|
|
|
|
<?php if (!empty($errorMessage ?? null)) : ?>
|
|
<div class="panel-error">
|
|
<strong>Unable to load data:</strong>
|
|
<span><?php echo htmlspecialchars($errorMessage); ?></span>
|
|
</div>
|
|
<?php elseif (empty($devices)) : ?>
|
|
<div class="panel-loading">
|
|
<span>No latency samples have been recorded yet.</span>
|
|
<span>Verify the watcher is running and devices are configured.</span>
|
|
</div>
|
|
<?php else : ?>
|
|
<div class="latency-table-wrapper">
|
|
<table class="latency-table">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col">Device</th>
|
|
<th scope="col">Host</th>
|
|
<th scope="col">Status</th>
|
|
<th scope="col">Latency (ms)</th>
|
|
<th scope="col">Last checked</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($devices as $device) : ?>
|
|
<?php
|
|
$status = $device['status'] ?? null;
|
|
$latency = $device['latency_ms'] ?? null;
|
|
$statusLabel = 'Unknown';
|
|
$statusClass = 'status-pill--unknown';
|
|
|
|
$trendUrl = 'trends/live/autochart.php?'
|
|
. http_build_query([
|
|
'primary' => 'latency:' . $device['id'],
|
|
'primary_label' => $device['label'],
|
|
'autostart' => '1',
|
|
'interval' => '5000',
|
|
]);
|
|
|
|
if ($status === 'up') {
|
|
$statusLabel = 'Online';
|
|
$statusClass = 'status-pill--up';
|
|
} elseif ($status === 'down') {
|
|
$statusLabel = 'Offline';
|
|
$statusClass = 'status-pill--down';
|
|
}
|
|
?>
|
|
<tr>
|
|
<td data-label="Device">
|
|
<a class="latency-link" href="<?php echo htmlspecialchars($trendUrl, ENT_QUOTES, 'UTF-8'); ?>" target="_blank" rel="noopener">
|
|
<?php echo htmlspecialchars($device['label']); ?>
|
|
</a>
|
|
</td>
|
|
<td data-label="Host"><?php echo htmlspecialchars($device['host']); ?></td>
|
|
<td data-label="Status">
|
|
<span class="status-pill <?php echo $statusClass; ?>">
|
|
<?php echo htmlspecialchars($statusLabel); ?>
|
|
</span>
|
|
</td>
|
|
<td data-label="Latency">
|
|
<?php echo $latency !== null ? number_format((float) $latency, 0) : '—'; ?>
|
|
</td>
|
|
<td data-label="Last checked">
|
|
<?php echo htmlspecialchars($device['checked_at_formatted'] ?? '—'); ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<footer class="latency-footnote">
|
|
<p>
|
|
Results update whenever <code>monitoring/latency_watcher.py</code> records a sample.
|
|
Configure devices in the <code>monitoring_devices</code> table and ensure the watcher
|
|
has database access.
|
|
</p>
|
|
</footer>
|
|
|
|
<?php
|
|
$payload = ob_get_clean();
|
|
$etag = '"' . md5($payload) . '"';
|
|
$clientEtag = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : null;
|
|
|
|
if ($clientEtag && $clientEtag === $etag) {
|
|
header('HTTP/1.1 304 Not Modified');
|
|
header('Cache-Control: no-cache, must-revalidate');
|
|
header('ETag: ' . $etag);
|
|
exit;
|
|
}
|
|
|
|
header('Cache-Control: no-cache, must-revalidate');
|
|
header('Content-Type: text/html; charset=utf-8');
|
|
header('ETag: ' . $etag);
|
|
|
|
echo $payload;
|