Files
proxmox/scripts/monitoring/create-monitoring-dashboard.sh
defiQUG fbda1b4beb
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
docs: Ledger Live integration, contract deploy learnings, NEXT_STEPS updates
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands
- CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround
- CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check
- NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere
- MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates
- LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 15:46:57 -08:00

272 lines
8.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Create Monitoring Dashboard
# Generates a simple HTML dashboard for monitoring status
set -euo pipefail
# Load IP configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Colors
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
create_dashboard() {
log_info "Creating monitoring dashboard..."
local dashboard_file="${PROJECT_ROOT}/logs/monitoring/dashboard.html"
mkdir -p "$(dirname "$dashboard_file")"
cat > "$dashboard_file" <<'DASHBOARD'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blockchain Monitoring Dashboard</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: #0f172a;
color: #e2e8f0;
padding: 20px;
}
.container { max-width: 1400px; margin: 0 auto; }
h1 {
color: #60a5fa;
margin-bottom: 30px;
font-size: 2.5em;
text-align: center;
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.status-card {
background: #1e293b;
border-radius: 12px;
padding: 20px;
border: 2px solid #334155;
transition: all 0.3s;
}
.status-card:hover {
border-color: #60a5fa;
transform: translateY(-2px);
}
.status-card.active { border-color: #10b981; }
.status-card.warning { border-color: #f59e0b; }
.status-card.error { border-color: #ef4444; }
.card-title {
font-size: 1.2em;
color: #94a3b8;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
margin-right: 8px;
}
.status-indicator.active { background: #10b981; box-shadow: 0 0 8px #10b981; }
.status-indicator.warning { background: #f59e0b; box-shadow: 0 0 8px #f59e0b; }
.status-indicator.error { background: #ef4444; box-shadow: 0 0 8px #ef4444; }
.card-value {
font-size: 2em;
color: #60a5fa;
font-weight: bold;
}
.log-section {
background: #1e293b;
border-radius: 12px;
padding: 20px;
margin-top: 20px;
border: 2px solid #334155;
}
.log-section h2 {
color: #60a5fa;
margin-bottom: 15px;
}
.log-viewer {
background: #0f172a;
border: 1px solid #334155;
border-radius: 8px;
padding: 15px;
font-family: 'Courier New', monospace;
font-size: 0.9em;
max-height: 400px;
overflow-y: auto;
color: #94a3b8;
}
.log-entry { margin-bottom: 5px; }
.log-entry.error { color: #ef4444; }
.log-entry.warning { color: #f59e0b; }
.log-entry.success { color: #10b981; }
.refresh-btn {
background: #3b82f6;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 1em;
margin-bottom: 20px;
}
.refresh-btn:hover { background: #2563eb; }
.timestamp {
color: #64748b;
font-size: 0.9em;
text-align: center;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>🔗 Blockchain Monitoring Dashboard</h1>
<button class="refresh-btn" onclick="location.reload()">🔄 Refresh</button>
<div class="status-grid" id="statusGrid">
<!-- Status cards will be populated by JavaScript -->
</div>
<div class="log-section">
<h2>Recent Activity</h2>
<div class="log-viewer" id="logViewer">
<!-- Logs will be populated by JavaScript -->
</div>
</div>
<div class="timestamp" id="timestamp"></div>
</div>
<script>
function fetchStatus() {
// This would normally fetch from an API
// For now, we'll use static data or file reading
const statusGrid = document.getElementById('statusGrid');
const logViewer = document.getElementById('logViewer');
// Example status data (replace with actual API calls)
const statuses = [
{ name: 'Block Production', status: 'active', value: 'Active', detail: 'Block: 1153290+' },
{ name: 'Validators', status: 'active', value: '5/5', detail: 'All validators running' },
{ name: 'Health Checks', status: 'active', value: 'OK', detail: 'All checks passing' },
{ name: 'Transaction Pool', status: 'active', value: 'Normal', detail: 'No stuck transactions' },
{ name: 'Network Sync', status: 'active', value: 'Synced', detail: 'All nodes synchronized' },
{ name: 'Consensus', status: 'active', value: 'QBFT', detail: 'Quorum maintained' }
];
statusGrid.innerHTML = statuses.map(s => `
<div class="status-card ${s.status}">
<div class="card-title">
<span><span class="status-indicator ${s.status}"></span>${s.name}</span>
</div>
<div class="card-value">${s.value}</div>
<div style="color: #94a3b8; margin-top: 5px;">${s.detail}</div>
</div>
`).join('');
logViewer.innerHTML = `
<div class="log-entry success">[${new Date().toLocaleTimeString()}] All systems operational</div>
<div class="log-entry">[${new Date().toLocaleTimeString()}] Health checks running normally</div>
<div class="log-entry">[${new Date().toLocaleTimeString()}] Block production active</div>
`;
document.getElementById('timestamp').textContent =
`Last updated: ${new Date().toLocaleString()}`;
}
// Initial load
fetchStatus();
// Auto-refresh every 30 seconds
setInterval(fetchStatus, 30000);
</script>
</body>
</html>
DASHBOARD
log_success "Dashboard created: $dashboard_file"
log_info "Open in browser: file://$dashboard_file"
}
create_dashboard_script() {
log_info "Creating dashboard update script..."
cat > "$SCRIPT_DIR/update-dashboard.sh" <<'DASHBOARDSCRIPT'
#!/usr/bin/env bash
# Update Monitoring Dashboard
# Fetches current status and updates dashboard
set -euo pipefail
# Load IP configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Source environment
if [ -f "$PROJECT_ROOT/smom-dbis-138/.env" ]; then
source "$PROJECT_ROOT/smom-dbis-138/.env" 2>/dev/null || true
fi
RPC_URL="${RPC_URL_138:-http://${RPC_CORE_1}:8545}"
# Get current block
BLOCK=$(cast block-number --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
# Get validator status (simplified)
VALIDATOR_COUNT=5
# Update dashboard with real data
# This would be integrated with the HTML dashboard
echo "Dashboard update script ready"
echo "Block: $BLOCK"
echo "Validators: $VALIDATOR_COUNT/5"
DASHBOARDSCRIPT
chmod +x "$SCRIPT_DIR/update-dashboard.sh"
log_success "update-dashboard.sh script created"
}
main() {
log_info "Creating monitoring dashboard..."
echo ""
create_dashboard
echo ""
create_dashboard_script
echo ""
log_success "Monitoring dashboard created!"
log_info "Dashboard location: logs/monitoring/dashboard.html"
log_info "You can open it in a web browser or set up a web server to serve it"
}
main "$@"