feat(daemon): modernize daemon logging with tables and color-coded output

- Modernize periodic status update with logger.logTable() and color-coded battery/runtime
- Modernize configuration loaded display with tables for UPS devices and groups
- Enhance power status change notifications with better colors and timestamps
- Modernize shutdown monitoring with real-time table display of UPS status
- Add color-coded CRITICAL indicators for emergency conditions
- Improve visual hierarchy with appropriate box styles (info, warning, error, success)
- Ensure consistent theming across all daemon log output
This commit is contained in:
2025-10-20 01:38:44 +00:00
parent 8516056f84
commit caced2718f

View File

@@ -310,29 +310,58 @@ export class NupstDaemon {
* Log the loaded configuration settings * Log the loaded configuration settings
*/ */
private logConfigLoaded(): void { private logConfigLoaded(): void {
const boxWidth = 50; const { theme } = require('./colors.ts');
logger.logBoxTitle('Configuration Loaded', boxWidth);
logger.log('');
if (this.config.upsDevices && this.config.upsDevices.length > 0) { logger.logBoxTitle('Configuration Loaded', 70, 'success');
logger.logBoxLine(`UPS Devices: ${this.config.upsDevices.length}`);
for (const ups of this.config.upsDevices) {
logger.logBoxLine(` - ${ups.name} (${ups.id}): ${ups.snmp.host}:${ups.snmp.port}`);
}
} else {
logger.logBoxLine('No UPS devices configured');
}
if (this.config.groups && this.config.groups.length > 0) {
logger.logBoxLine(`Groups: ${this.config.groups.length}`);
for (const group of this.config.groups) {
logger.logBoxLine(` - ${group.name} (${group.id}): ${group.mode} mode`);
}
} else {
logger.logBoxLine('No Groups configured');
}
logger.logBoxLine(`Check Interval: ${this.config.checkInterval / 1000} seconds`); logger.logBoxLine(`Check Interval: ${this.config.checkInterval / 1000} seconds`);
logger.logBoxEnd(); logger.logBoxEnd();
logger.log('');
// Display UPS devices in a table
if (this.config.upsDevices && this.config.upsDevices.length > 0) {
logger.info(`UPS Devices (${this.config.upsDevices.length}):`);
const upsColumns: Array<{ header: string; key: string; align?: 'left' | 'right'; color?: (val: string) => string }> = [
{ header: 'Name', key: 'name', align: 'left', color: theme.highlight },
{ header: 'ID', key: 'id', align: 'left', color: theme.dim },
{ header: 'Host:Port', key: 'host', align: 'left', color: theme.info },
{ header: 'Battery/Runtime', key: 'thresholds', align: 'left' },
];
const upsRows: Array<Record<string, string>> = this.config.upsDevices.map((ups) => ({
name: ups.name,
id: ups.id,
host: `${ups.snmp.host}:${ups.snmp.port}`,
thresholds: `${ups.thresholds.battery}% / ${ups.thresholds.runtime} min`,
}));
logger.logTable(upsColumns, upsRows);
logger.log('');
} else {
logger.warn('No UPS devices configured');
logger.log('');
}
// Display groups in a table
if (this.config.groups && this.config.groups.length > 0) {
logger.info(`Groups (${this.config.groups.length}):`);
const groupColumns: Array<{ header: string; key: string; align?: 'left' | 'right'; color?: (val: string) => string }> = [
{ header: 'Name', key: 'name', align: 'left', color: theme.highlight },
{ header: 'ID', key: 'id', align: 'left', color: theme.dim },
{ header: 'Mode', key: 'mode', align: 'left', color: theme.info },
];
const groupRows: Array<Record<string, string>> = this.config.groups.map((group) => ({
name: group.name,
id: group.id,
mode: group.mode,
}));
logger.logTable(groupColumns, groupRows);
logger.log('');
}
} }
/** /**
@@ -428,9 +457,14 @@ export class NupstDaemon {
// Check if power status changed // Check if power status changed
if (currentStatus && currentStatus.powerStatus !== status.powerStatus) { if (currentStatus && currentStatus.powerStatus !== status.powerStatus) {
logger.logBoxTitle(`Power Status Change: ${ups.name}`, 50); const { theme, formatPowerStatus } = require('./colors.ts');
logger.logBoxLine(`Status changed: ${currentStatus.powerStatus}${status.powerStatus}`); logger.log('');
logger.logBoxTitle(`Power Status Change: ${ups.name}`, 60, 'warning');
logger.logBoxLine(`Previous: ${formatPowerStatus(currentStatus.powerStatus)}`);
logger.logBoxLine(`Current: ${formatPowerStatus(status.powerStatus)}`);
logger.logBoxLine(`Time: ${new Date().toISOString()}`);
logger.logBoxEnd(); logger.logBoxEnd();
logger.log('');
updatedStatus.lastStatusChange = currentTime; updatedStatus.lastStatusChange = currentTime;
} }
@@ -452,21 +486,41 @@ export class NupstDaemon {
*/ */
private logAllUpsStatus(): void { private logAllUpsStatus(): void {
const timestamp = new Date().toISOString(); const timestamp = new Date().toISOString();
const boxWidth = 60;
logger.logBoxTitle('Periodic Status Update', boxWidth); logger.log('');
logger.logBoxTitle('Periodic Status Update', 70, 'info');
logger.logBoxLine(`Timestamp: ${timestamp}`); logger.logBoxLine(`Timestamp: ${timestamp}`);
logger.logBoxLine(''); logger.logBoxEnd();
logger.log('');
// Import theme and symbols for coloring
const { theme, symbols, getBatteryColor, getRuntimeColor, formatPowerStatus } = require('./colors.ts');
// Build table data
const columns: Array<{ header: string; key: string; align?: 'left' | 'right'; color?: (val: string) => string }> = [
{ header: 'UPS Name', key: 'name', align: 'left', color: theme.highlight },
{ header: 'ID', key: 'id', align: 'left', color: theme.dim },
{ header: 'Power Status', key: 'powerStatus', align: 'left' },
{ header: 'Battery', key: 'battery', align: 'right' },
{ header: 'Runtime', key: 'runtime', align: 'right' },
];
const rows: Array<Record<string, string>> = [];
for (const [id, status] of this.upsStatus.entries()) { for (const [id, status] of this.upsStatus.entries()) {
logger.logBoxLine(`UPS: ${status.name} (${id})`); const batteryColor = getBatteryColor(status.batteryCapacity);
logger.logBoxLine(` Power Status: ${status.powerStatus}`); const runtimeColor = getRuntimeColor(status.batteryRuntime);
logger.logBoxLine(
` Battery: ${status.batteryCapacity}% | Runtime: ${status.batteryRuntime} min`, rows.push({
); name: status.name,
logger.logBoxLine(''); id: id,
powerStatus: formatPowerStatus(status.powerStatus),
battery: batteryColor(status.batteryCapacity + '%'),
runtime: runtimeColor(status.batteryRuntime + ' min'),
});
} }
logger.logBoxEnd(); logger.logTable(columns, rows);
logger.log('');
} }
/** /**
@@ -745,38 +799,63 @@ export class NupstDaemon {
const MAX_MONITORING_TIME = 5 * 60 * 1000; // Max 5 minutes of monitoring const MAX_MONITORING_TIME = 5 * 60 * 1000; // Max 5 minutes of monitoring
const startTime = Date.now(); const startTime = Date.now();
logger.log( const { theme, getBatteryColor, getRuntimeColor } = require('./colors.ts');
`Emergency shutdown threshold: ${EMERGENCY_RUNTIME_THRESHOLD} minutes remaining battery runtime`,
); logger.log('');
logger.logBoxTitle('Shutdown Monitoring Active', 60, 'warning');
logger.logBoxLine(`Emergency threshold: ${EMERGENCY_RUNTIME_THRESHOLD} minutes runtime`);
logger.logBoxLine(`Check interval: ${CHECK_INTERVAL / 1000} seconds`);
logger.logBoxLine(`Max monitoring time: ${MAX_MONITORING_TIME / 1000} seconds`);
logger.logBoxEnd();
logger.log('');
// Continue monitoring until max monitoring time is reached // Continue monitoring until max monitoring time is reached
while (Date.now() - startTime < MAX_MONITORING_TIME) { while (Date.now() - startTime < MAX_MONITORING_TIME) {
try { try {
logger.log('Checking UPS status during shutdown...'); logger.info('Checking UPS status during shutdown...');
// Build table for UPS status during shutdown
const columns: Array<{ header: string; key: string; align?: 'left' | 'right'; color?: (val: string) => string }> = [
{ header: 'UPS Name', key: 'name', align: 'left', color: theme.highlight },
{ header: 'Battery', key: 'battery', align: 'right' },
{ header: 'Runtime', key: 'runtime', align: 'right' },
{ header: 'Status', key: 'status', align: 'left' },
];
const rows: Array<Record<string, string>> = [];
let emergencyDetected = false;
let emergencyUps: any = null;
// Check all UPS devices // Check all UPS devices
for (const ups of this.config.upsDevices) { for (const ups of this.config.upsDevices) {
try { try {
const status = await this.snmp.getUpsStatus(ups.snmp); const status = await this.snmp.getUpsStatus(ups.snmp);
logger.log( const batteryColor = getBatteryColor(status.batteryCapacity);
`UPS ${ups.name}: Battery ${status.batteryCapacity}%, Runtime: ${status.batteryRuntime} minutes`, const runtimeColor = getRuntimeColor(status.batteryRuntime);
);
// If any UPS battery runtime gets critically low, force immediate shutdown const isCritical = status.batteryRuntime < EMERGENCY_RUNTIME_THRESHOLD;
if (status.batteryRuntime < EMERGENCY_RUNTIME_THRESHOLD) {
logger.logBoxTitle('EMERGENCY SHUTDOWN', 50); rows.push({
logger.logBoxLine( name: ups.name,
`UPS ${ups.name} runtime critically low: ${status.batteryRuntime} minutes`, battery: batteryColor(status.batteryCapacity + '%'),
); runtime: runtimeColor(status.batteryRuntime + ' min'),
logger.logBoxLine('Forcing immediate shutdown!'); status: isCritical ? theme.error('CRITICAL!') : theme.success('OK'),
logger.logBoxEnd(); });
// Force immediate shutdown // If any UPS battery runtime gets critically low, flag for immediate shutdown
await this.forceImmediateShutdown(); if (isCritical && !emergencyDetected) {
return; emergencyDetected = true;
emergencyUps = { ups, status };
} }
} catch (upsError) { } catch (upsError) {
rows.push({
name: ups.name,
battery: theme.error('N/A'),
runtime: theme.error('N/A'),
status: theme.error('ERROR'),
});
logger.error( logger.error(
`Error checking UPS ${ups.name} during shutdown: ${ `Error checking UPS ${ups.name} during shutdown: ${
upsError instanceof Error ? upsError.message : String(upsError) upsError instanceof Error ? upsError.message : String(upsError)
@@ -785,6 +864,27 @@ export class NupstDaemon {
} }
} }
// Display the table
logger.logTable(columns, rows);
logger.log('');
// If emergency detected, trigger immediate shutdown
if (emergencyDetected && emergencyUps) {
logger.log('');
logger.logBoxTitle('EMERGENCY SHUTDOWN', 60, 'error');
logger.logBoxLine(
`UPS ${emergencyUps.ups.name} runtime critically low: ${emergencyUps.status.batteryRuntime} minutes`,
);
logger.logBoxLine(`Emergency threshold: ${EMERGENCY_RUNTIME_THRESHOLD} minutes`);
logger.logBoxLine('Forcing immediate shutdown!');
logger.logBoxEnd();
logger.log('');
// Force immediate shutdown
await this.forceImmediateShutdown();
return;
}
// Wait before checking again // Wait before checking again
await this.sleep(CHECK_INTERVAL); await this.sleep(CHECK_INTERVAL);
} catch (error) { } catch (error) {
@@ -797,7 +897,9 @@ export class NupstDaemon {
} }
} }
logger.log('UPS monitoring during shutdown completed'); logger.log('');
logger.success('UPS monitoring during shutdown completed');
logger.log('');
} }
/** /**