mirror of
https://github.com/asimonson1125/asimonson1125.github.io.git
synced 2026-02-24 21:09:49 -06:00
productionalizing?
This commit is contained in:
@@ -3,7 +3,7 @@ from flask_minify import Minify
|
|||||||
import json
|
import json
|
||||||
import werkzeug.exceptions as HTTPerror
|
import werkzeug.exceptions as HTTPerror
|
||||||
from config import *
|
from config import *
|
||||||
from monitor import monitor
|
from monitor import monitor, SERVICES
|
||||||
|
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
|
|
||||||
@@ -43,6 +43,7 @@ pages['projects']['skillList'] = skillList
|
|||||||
pages['projects']['projects'] = proj
|
pages['projects']['projects'] = proj
|
||||||
pages['home']['books'] = books
|
pages['home']['books'] = books
|
||||||
pages['books']['books'] = books
|
pages['books']['books'] = books
|
||||||
|
pages['status']['services'] = SERVICES
|
||||||
|
|
||||||
@app.route('/api/status')
|
@app.route('/api/status')
|
||||||
def api_status():
|
def api_status():
|
||||||
|
|||||||
@@ -30,15 +30,9 @@ SERVICES = [
|
|||||||
'timeout': 10
|
'timeout': 10
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'pass',
|
'id': 'balls',
|
||||||
'name': 'pass.asimonson.com',
|
'name': 'balls.asimonson.com',
|
||||||
'url': 'https://pass.asimonson.com',
|
'url': 'https://balls.asimonson.com',
|
||||||
'timeout': 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'id': 'ssh',
|
|
||||||
'name': 'ssh.asimonson.com',
|
|
||||||
'url': 'https://ssh.asimonson.com',
|
|
||||||
'timeout': 10
|
'timeout': 10
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -182,8 +176,22 @@ class ServiceMonitor:
|
|||||||
if datetime.fromisoformat(c['timestamp']) > cutoff
|
if datetime.fromisoformat(c['timestamp']) > cutoff
|
||||||
]
|
]
|
||||||
|
|
||||||
if not checks:
|
if not checks:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Require minimum data coverage for the time period
|
||||||
|
# Calculate expected number of checks for this period
|
||||||
|
expected_checks = (hours * 3600) / CHECK_INTERVAL
|
||||||
|
|
||||||
|
# Require at least 50% of expected checks to show this metric
|
||||||
|
minimum_checks = max(3, expected_checks * 0.5)
|
||||||
|
|
||||||
|
if len(checks) < minimum_checks:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# For all-time, require at least 3 checks
|
||||||
|
if len(checks) < 3:
|
||||||
|
return None
|
||||||
|
|
||||||
online_count = sum(1 for c in checks if c['status'] == 'online')
|
online_count = sum(1 for c in checks if c['status'] == 'online')
|
||||||
uptime = (online_count / len(checks)) * 100
|
uptime = (online_count / len(checks)) * 100
|
||||||
|
|||||||
@@ -104,11 +104,30 @@ strong {
|
|||||||
color: #ecebeb;
|
color: #ecebeb;
|
||||||
}
|
}
|
||||||
|
|
||||||
p, li {
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1.5em;
|
||||||
|
color: #a8a8a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
color: #a8a8a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: #ecebeb;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, li, span {
|
||||||
color: rgb(212, 212, 212);
|
color: rgb(212, 212, 212);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: .8rem;
|
||||||
|
}
|
||||||
|
|
||||||
a, a p {
|
a, a p {
|
||||||
color: #a0a0a0a0;
|
color: #a0a0a0a0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@@ -1297,20 +1316,116 @@ tr {
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-info {
|
/* Overall Status Bar */
|
||||||
|
/* Overall Status Bar */
|
||||||
|
.overall-status-bar {
|
||||||
|
background: rgba(24, 24, 24, 0.95);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
padding: 2em;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
border-top: solid 4px rgba(139, 36, 36, 0.5);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
transition: border-color 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-bar.all-operational {
|
||||||
|
border-top-color: rgba(76, 175, 80, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-bar.partial-outage {
|
||||||
|
border-top-color: rgba(255, 193, 7, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-bar.major-outage {
|
||||||
|
border-top-color: rgba(244, 67, 54, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 2em;
|
flex-wrap: wrap;
|
||||||
padding: 1em;
|
gap: 2em;
|
||||||
background: rgba(24, 24, 24, 0.85);
|
|
||||||
border-radius: 0.5em;
|
|
||||||
border: solid 2px rgba(139, 36, 36, 0.5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-info span {
|
.overall-status-indicator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
line-height: 1;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-icon.operational {
|
||||||
|
color: #4caf50;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-icon.partial {
|
||||||
|
color: #ffc107;
|
||||||
|
animation: pulse-icon 1.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-icon.major {
|
||||||
|
color: #f44336;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from { transform: rotate(0deg); }
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-icon {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.5; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: #ecebeb;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-subtitle {
|
||||||
|
margin: 0.3em 0 0 0;
|
||||||
|
font-size: 1rem;
|
||||||
color: #a8a8a8;
|
color: #a8a8a8;
|
||||||
font-size: 0.9rem;
|
}
|
||||||
|
|
||||||
|
.overall-status-metrics {
|
||||||
|
display: flex;
|
||||||
|
gap: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1em 1.5em;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-number {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ecebeb;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-label {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #a8a8a8;
|
||||||
|
margin-top: 0.3em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#refreshBtn {
|
#refreshBtn {
|
||||||
@@ -1504,35 +1619,28 @@ tr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.uptime-values strong {
|
.uptime-values strong {
|
||||||
color: #4caf50;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-info-box {
|
/* Uptime color coding based on percentage */
|
||||||
background: rgba(24, 24, 24, 0.85);
|
.uptime-excellent {
|
||||||
border-radius: 0.5em;
|
color: #4caf50 !important; /* 99%+ - Green */
|
||||||
padding: 1.5em;
|
|
||||||
border: solid 2px rgba(139, 36, 36, 0.5);
|
|
||||||
margin-top: 2em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-info-box h4 {
|
.uptime-good {
|
||||||
margin-top: 0;
|
color: #8bc34a !important; /* 95-99% - Light green */
|
||||||
color: #ecebeb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-info-box ul {
|
.uptime-fair {
|
||||||
margin: 0;
|
color: #ffc107 !important; /* 90-95% - Yellow */
|
||||||
padding-left: 1.5em;
|
|
||||||
color: #a8a8a8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-info-box li {
|
.uptime-poor {
|
||||||
margin-bottom: 0.5em;
|
color: #f44336 !important; /* <90% - Red */
|
||||||
color: #a8a8a8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-info-box strong {
|
.uptime-none {
|
||||||
color: #ecebeb;
|
color: #888 !important; /* No data - Gray */
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1400px) {
|
@media screen and (max-width: 1400px) {
|
||||||
@@ -1549,4 +1657,19 @@ tr {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.overall-status-content {
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-indicator {
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overall-status-metrics {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -43,6 +43,9 @@ function updateStatusDisplay(data) {
|
|||||||
updateServiceCard(service);
|
updateServiceCard(service);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update overall status
|
||||||
|
updateOverallStatus(data.services);
|
||||||
|
|
||||||
// Re-enable refresh button
|
// Re-enable refresh button
|
||||||
const refreshBtn = document.getElementById('refreshBtn');
|
const refreshBtn = document.getElementById('refreshBtn');
|
||||||
if (refreshBtn) {
|
if (refreshBtn) {
|
||||||
@@ -109,24 +112,29 @@ function updateServiceCard(service) {
|
|||||||
if (uptimeDisplay && service.uptime) {
|
if (uptimeDisplay && service.uptime) {
|
||||||
const uptimeHTML = [];
|
const uptimeHTML = [];
|
||||||
|
|
||||||
if (service.uptime['24h'] !== null) {
|
// Helper function to get color class based on uptime percentage
|
||||||
uptimeHTML.push(`24h: <strong>${service.uptime['24h']}%</strong>`);
|
const getUptimeClass = (value) => {
|
||||||
}
|
if (value === null) return 'uptime-none';
|
||||||
if (service.uptime['7d'] !== null) {
|
if (value >= 99) return 'uptime-excellent';
|
||||||
uptimeHTML.push(`7d: <strong>${service.uptime['7d']}%</strong>`);
|
if (value >= 95) return 'uptime-good';
|
||||||
}
|
if (value >= 90) return 'uptime-fair';
|
||||||
if (service.uptime['30d'] !== null) {
|
return 'uptime-poor';
|
||||||
uptimeHTML.push(`30d: <strong>${service.uptime['30d']}%</strong>`);
|
};
|
||||||
}
|
|
||||||
if (service.uptime.all_time !== null) {
|
|
||||||
uptimeHTML.push(`All: <strong>${service.uptime.all_time}%</strong>`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uptimeHTML.length > 0) {
|
// Helper function to format uptime value
|
||||||
uptimeDisplay.innerHTML = uptimeHTML.join(' | ');
|
const formatUptime = (value, label) => {
|
||||||
} else {
|
const display = value !== null ? `${value}%` : '--';
|
||||||
uptimeDisplay.textContent = 'No data yet';
|
const colorClass = getUptimeClass(value);
|
||||||
}
|
return `${label}: <strong class="${colorClass}">${display}</strong>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add all uptime metrics
|
||||||
|
uptimeHTML.push(formatUptime(service.uptime['24h'], '24h'));
|
||||||
|
uptimeHTML.push(formatUptime(service.uptime['7d'], '7d'));
|
||||||
|
uptimeHTML.push(formatUptime(service.uptime['30d'], '30d'));
|
||||||
|
uptimeHTML.push(formatUptime(service.uptime.all_time, 'All'));
|
||||||
|
|
||||||
|
uptimeDisplay.innerHTML = uptimeHTML.join(' | ');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update total checks
|
// Update total checks
|
||||||
@@ -135,6 +143,68 @@ function updateServiceCard(service) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update overall status bar
|
||||||
|
*/
|
||||||
|
function updateOverallStatus(services) {
|
||||||
|
const overallBar = document.getElementById('overallStatus');
|
||||||
|
const icon = overallBar.querySelector('.overall-status-icon');
|
||||||
|
const title = overallBar.querySelector('.overall-status-title');
|
||||||
|
const subtitle = overallBar.querySelector('.overall-status-subtitle');
|
||||||
|
const onlineCount = document.getElementById('onlineCount');
|
||||||
|
const totalCount = document.getElementById('totalCount');
|
||||||
|
|
||||||
|
// Count service statuses
|
||||||
|
const total = services.length;
|
||||||
|
const online = services.filter(s => s.status === 'online').length;
|
||||||
|
const degraded = services.filter(s => s.status === 'degraded' || s.status === 'timeout').length;
|
||||||
|
const offline = services.filter(s => s.status === 'offline').length;
|
||||||
|
|
||||||
|
// Update counts
|
||||||
|
onlineCount.textContent = online;
|
||||||
|
totalCount.textContent = total;
|
||||||
|
|
||||||
|
// Remove all status classes
|
||||||
|
overallBar.classList.remove('all-operational', 'partial-outage', 'major-outage');
|
||||||
|
icon.classList.remove('operational', 'partial', 'major', 'loading');
|
||||||
|
|
||||||
|
// Determine overall status
|
||||||
|
if (online === total) {
|
||||||
|
// All systems operational
|
||||||
|
overallBar.classList.add('all-operational');
|
||||||
|
icon.classList.add('operational');
|
||||||
|
icon.textContent = '✓';
|
||||||
|
title.textContent = 'All Systems Operational';
|
||||||
|
subtitle.textContent = `All ${total} services are running normally`;
|
||||||
|
} else if (offline >= Math.ceil(total / 2)) {
|
||||||
|
// Major outage (50% or more offline)
|
||||||
|
overallBar.classList.add('major-outage');
|
||||||
|
icon.classList.add('major');
|
||||||
|
icon.textContent = '✕';
|
||||||
|
title.textContent = 'Major Outage';
|
||||||
|
subtitle.textContent = `${offline} service${offline !== 1 ? 's' : ''} offline, ${degraded} degraded`;
|
||||||
|
} else if (offline > 0 || degraded > 0) {
|
||||||
|
// Partial outage
|
||||||
|
overallBar.classList.add('partial-outage');
|
||||||
|
icon.classList.add('partial');
|
||||||
|
icon.textContent = '⚠';
|
||||||
|
title.textContent = 'Partial Outage';
|
||||||
|
if (offline > 0 && degraded > 0) {
|
||||||
|
subtitle.textContent = `${offline} offline, ${degraded} degraded`;
|
||||||
|
} else if (offline > 0) {
|
||||||
|
subtitle.textContent = `${offline} service${offline !== 1 ? 's' : ''} offline`;
|
||||||
|
} else {
|
||||||
|
subtitle.textContent = `${degraded} service${degraded !== 1 ? 's' : ''} degraded`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Unknown state
|
||||||
|
icon.classList.add('loading');
|
||||||
|
icon.textContent = '◐';
|
||||||
|
title.textContent = 'Status Unknown';
|
||||||
|
subtitle.textContent = 'Waiting for service data';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show error message
|
* Show error message
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,145 +0,0 @@
|
|||||||
{
|
|
||||||
"last_check": "2026-02-11T14:53:09.045018",
|
|
||||||
"services": {
|
|
||||||
"main": {
|
|
||||||
"name": "asimonson.com",
|
|
||||||
"url": "https://asimonson.com",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 170,
|
|
||||||
"status_code": 200,
|
|
||||||
"last_online": "2026-02-11T14:53:08.089141",
|
|
||||||
"checks": [
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:45:35.008804",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 171,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:51:02.673733",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 138,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:53:08.089141",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 170,
|
|
||||||
"status_code": 200
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"files": {
|
|
||||||
"name": "files.asimonson.com",
|
|
||||||
"url": "https://files.asimonson.com",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 215,
|
|
||||||
"status_code": 200,
|
|
||||||
"last_online": "2026-02-11T14:53:08.259522",
|
|
||||||
"checks": [
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:45:35.180195",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 285,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:51:02.812769",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 259,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:53:08.259522",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 215,
|
|
||||||
"status_code": 200
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"git": {
|
|
||||||
"name": "git.asimonson.com",
|
|
||||||
"url": "https://git.asimonson.com",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 145,
|
|
||||||
"status_code": 200,
|
|
||||||
"last_online": "2026-02-11T14:53:08.475376",
|
|
||||||
"checks": [
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:45:35.465748",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 297,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:51:03.072293",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 293,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:53:08.475376",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 145,
|
|
||||||
"status_code": 200
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pass": {
|
|
||||||
"name": "pass.asimonson.com",
|
|
||||||
"url": "https://pass.asimonson.com",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 160,
|
|
||||||
"status_code": 200,
|
|
||||||
"last_online": "2026-02-11T14:53:08.621016",
|
|
||||||
"checks": [
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:45:35.763775",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 253,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:51:03.365544",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 228,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:53:08.621016",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 160,
|
|
||||||
"status_code": 200
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ssh": {
|
|
||||||
"name": "ssh.asimonson.com",
|
|
||||||
"url": "https://ssh.asimonson.com",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 263,
|
|
||||||
"status_code": 200,
|
|
||||||
"last_online": "2026-02-11T14:53:08.781704",
|
|
||||||
"checks": [
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:45:36.017180",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 378,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:51:03.594307",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 411,
|
|
||||||
"status_code": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-11T14:53:08.781704",
|
|
||||||
"status": "online",
|
|
||||||
"response_time": 263,
|
|
||||||
"status_code": 200
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,160 +2,18 @@
|
|||||||
<div class="foreground"></div>
|
<div class="foreground"></div>
|
||||||
<div class="foregroundContent">
|
<div class="foregroundContent">
|
||||||
<h2 class='concentratedHead'>Service Status Monitor</h2>
|
<h2 class='concentratedHead'>Service Status Monitor</h2>
|
||||||
<p class="status-subtitle">Automated monitoring of asimonson.com services</p>
|
|
||||||
|
|
||||||
<div class="status-info">
|
|
||||||
<div>
|
|
||||||
<span id="lastUpdate">Last checked: Loading...</span>
|
|
||||||
<br>
|
|
||||||
<span id="nextUpdate" style="font-size: 0.85em; color: #888;">Next check: --</span>
|
|
||||||
</div>
|
|
||||||
<button id="refreshBtn" onclick="refreshStatus()">Refresh Now</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="status-container">
|
|
||||||
<div class="status-card" id="status-main">
|
|
||||||
<div class="status-header">
|
|
||||||
<h3>asimonson.com</h3>
|
|
||||||
<div class="status-indicator">
|
|
||||||
<span class="status-dot loading"></span>
|
|
||||||
<span class="status-text">Loading...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-details">
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Response Time:</span>
|
|
||||||
<span class="metric-value" id="time-main">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Status Code:</span>
|
|
||||||
<span class="metric-value" id="code-main">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Total Checks:</span>
|
|
||||||
<span class="metric-value" id="checks-main">--</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-uptime">
|
|
||||||
<div class="uptime-label">Uptime:</div>
|
|
||||||
<div class="uptime-values" id="uptime-main">Loading...</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="status-card" id="status-files">
|
|
||||||
<div class="status-header">
|
|
||||||
<h3>files.asimonson.com</h3>
|
|
||||||
<div class="status-indicator">
|
|
||||||
<span class="status-dot loading"></span>
|
|
||||||
<span class="status-text">Loading...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-details">
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Response Time:</span>
|
|
||||||
<span class="metric-value" id="time-files">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Status Code:</span>
|
|
||||||
<span class="metric-value" id="code-files">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Total Checks:</span>
|
|
||||||
<span class="metric-value" id="checks-files">--</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-uptime">
|
|
||||||
<div class="uptime-label">Uptime:</div>
|
|
||||||
<div class="uptime-values" id="uptime-files">Loading...</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="status-card" id="status-git">
|
|
||||||
<div class="status-header">
|
|
||||||
<h3>git.asimonson.com</h3>
|
|
||||||
<div class="status-indicator">
|
|
||||||
<span class="status-dot loading"></span>
|
|
||||||
<span class="status-text">Loading...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-details">
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Response Time:</span>
|
|
||||||
<span class="metric-value" id="time-git">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Status Code:</span>
|
|
||||||
<span class="metric-value" id="code-git">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Total Checks:</span>
|
|
||||||
<span class="metric-value" id="checks-git">--</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-uptime">
|
|
||||||
<div class="uptime-label">Uptime:</div>
|
|
||||||
<div class="uptime-values" id="uptime-git">Loading...</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="status-card" id="status-pass">
|
|
||||||
<div class="status-header">
|
|
||||||
<h3>pass.asimonson.com</h3>
|
|
||||||
<div class="status-indicator">
|
|
||||||
<span class="status-dot loading"></span>
|
|
||||||
<span class="status-text">Loading...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-details">
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Response Time:</span>
|
|
||||||
<span class="metric-value" id="time-pass">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Status Code:</span>
|
|
||||||
<span class="metric-value" id="code-pass">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Total Checks:</span>
|
|
||||||
<span class="metric-value" id="checks-pass">--</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-uptime">
|
|
||||||
<div class="uptime-label">Uptime:</div>
|
|
||||||
<div class="uptime-values" id="uptime-pass">Loading...</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="status-card" id="status-ssh">
|
|
||||||
<div class="status-header">
|
|
||||||
<h3>ssh.asimonson.com</h3>
|
|
||||||
<div class="status-indicator">
|
|
||||||
<span class="status-dot loading"></span>
|
|
||||||
<span class="status-text">Loading...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-details">
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Response Time:</span>
|
|
||||||
<span class="metric-value" id="time-ssh">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Status Code:</span>
|
|
||||||
<span class="metric-value" id="code-ssh">--</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-metric">
|
|
||||||
<span class="metric-label">Total Checks:</span>
|
|
||||||
<span class="metric-value" id="checks-ssh">--</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-uptime">
|
|
||||||
<div class="uptime-label">Uptime:</div>
|
|
||||||
<div class="uptime-values" id="uptime-ssh">Loading...</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="status-legend">
|
<div class="status-legend">
|
||||||
|
<div class='flex spaceBetween'>
|
||||||
|
<div>
|
||||||
|
<span id="lastUpdate">Last checked: Loading...</span>
|
||||||
|
<br />
|
||||||
|
<span id="nextUpdate">Next check: --</span>
|
||||||
|
</div>
|
||||||
|
<button id="refreshBtn" onclick="refreshStatus()">Refresh Now</button>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
<h4>Status Legend</h4>
|
<h4>Status Legend</h4>
|
||||||
<div class="legend-items">
|
<div class="legend-items">
|
||||||
<div class="legend-item">
|
<div class="legend-item">
|
||||||
@@ -173,13 +31,67 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-info-box">
|
<!-- Overall Status Bar -->
|
||||||
|
<div class="overall-status-bar" id="overallStatus">
|
||||||
|
<div class="overall-status-content">
|
||||||
|
<div class="overall-status-indicator">
|
||||||
|
<span class="overall-status-icon loading">◐</span>
|
||||||
|
<div>
|
||||||
|
<h3 class="overall-status-title">Checking Systems...</h3>
|
||||||
|
<p class="overall-status-subtitle">Loading service status</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overall-status-metrics">
|
||||||
|
<div class="metric-box">
|
||||||
|
<span class="metric-number" id="onlineCount">--</span>
|
||||||
|
<span class="metric-label">Online</span>
|
||||||
|
</div>
|
||||||
|
<div class="metric-box">
|
||||||
|
<span class="metric-number" id="totalCount">--</span>
|
||||||
|
<span class="metric-label">Total</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status-container">
|
||||||
|
{% for service in var.services %}
|
||||||
|
<a href="https://{{ service.url }}">
|
||||||
|
<div class="status-card" id="status-{{ service.id }}">
|
||||||
|
<div class="status-header">
|
||||||
|
<h3>{{ service.name }}</h3>
|
||||||
|
<div class="status-indicator">
|
||||||
|
<span class="status-dot loading"></span>
|
||||||
|
<span class="status-text">Loading...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status-details">
|
||||||
|
<div class="status-metric">
|
||||||
|
<span class="metric-label">Response Time:</span>
|
||||||
|
<span class="metric-value" id="time-{{ service.id }}">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-metric">
|
||||||
|
<span class="metric-label">Status Code:</span>
|
||||||
|
<span class="metric-value" id="code-{{ service.id }}">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-metric">
|
||||||
|
<span class="metric-label">Total Checks:</span>
|
||||||
|
<span class="metric-value" id="checks-{{ service.id }}">--</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status-uptime">
|
||||||
|
<div class="uptime-label">Uptime:</div>
|
||||||
|
<div class="uptime-values" id="uptime-{{ service.id }}">Loading...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status-legend">
|
||||||
<h4>About This Monitor</h4>
|
<h4>About This Monitor</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>Check Frequency:</strong> Services are checked automatically every 2 hours from the server</li>
|
<li><strong>Check Frequency:</strong> Services are checked automatically every 30 minutes from the server</li>
|
||||||
<li><strong>Uptime Calculation:</strong> Based on historical check data (24h, 7d, 30d, and all-time)</li>
|
|
||||||
<li><strong>Response Time:</strong> Time taken to receive a response from the service</li>
|
|
||||||
<li><strong>Status Code:</strong> HTTP response code from the service</li>
|
|
||||||
<li><strong>Page Refresh:</strong> This page auto-refreshes every 5 minutes to show latest data</li>
|
<li><strong>Page Refresh:</strong> This page auto-refreshes every 5 minutes to show latest data</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user