mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-05 16:37:46 +00:00
feat: enhance API error handling and improve alert message formatting
This commit is contained in:
@@ -828,6 +828,15 @@ if (process.env.NODE_ENV === 'production') {
|
||||
app.use((req: Request, res: Response) => {
|
||||
if (!req.path.startsWith('/api')) {
|
||||
res.sendFile('index.html', { root: 'public' });
|
||||
} else {
|
||||
res.status(404).json({ error: 'API endpoint not found' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// In development, still need to catch 404s for API to prevent hangs
|
||||
app.use((req: Request, res: Response) => {
|
||||
if (req.path.startsWith('/api')) {
|
||||
res.status(404).json({ error: 'API endpoint not found' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,25 @@ import { NotificationService } from './NotificationService';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
const getMetricDetails = (metric: string): { name: string, unit: string } => {
|
||||
switch (metric) {
|
||||
case 'cpu_percent': return { name: 'CPU usage', unit: '%' };
|
||||
case 'memory_percent': return { name: 'Memory usage', unit: '%' };
|
||||
case 'memory_mb': return { name: 'Memory allocation', unit: ' MB' };
|
||||
case 'net_rx': return { name: 'Inbound network traffic', unit: ' MB/s' };
|
||||
case 'net_tx': return { name: 'Outbound network traffic', unit: ' MB/s' };
|
||||
case 'restart_count': return { name: 'Restart count', unit: ' restarts' };
|
||||
default: return { name: metric, unit: '' };
|
||||
}
|
||||
};
|
||||
|
||||
const getOperatorPhrase = (operator: string): string => {
|
||||
if (['>', '>='].includes(operator)) return 'has exceeded your threshold of';
|
||||
if (['<', '<='].includes(operator)) return 'has dropped below your threshold of';
|
||||
if (operator === '==') return 'has reached your threshold of';
|
||||
return `triggered the operator ${operator}`;
|
||||
};
|
||||
|
||||
interface AlertState {
|
||||
breachStartedAt: number; // timestamp when the rule first breached
|
||||
}
|
||||
@@ -230,10 +249,18 @@ export class MonitorService {
|
||||
const requiredCooldownMs = rule.cooldown_mins * 60 * 1000;
|
||||
|
||||
if (timeSinceLastFired >= requiredCooldownMs) {
|
||||
// FIRE THE ALERT!
|
||||
// Formatted Alert Message
|
||||
const { name: metricName, unit } = getMetricDetails(rule.metric);
|
||||
const operatorPhrase = getOperatorPhrase(rule.operator);
|
||||
|
||||
const safeCurrent = typeof currentValue === 'number' ? Number(currentValue.toFixed(2)) : currentValue;
|
||||
const safeThreshold = typeof rule.threshold === 'number' ? Number(rule.threshold.toFixed(2)) : rule.threshold;
|
||||
|
||||
const message = `The **${metricName}** for **${rule.stack_name}** ${operatorPhrase} **${safeThreshold}${unit}** (Currently: ${safeCurrent}${unit}).`;
|
||||
|
||||
await NotificationService.getInstance().dispatchAlert(
|
||||
'warning',
|
||||
`Alert for **${rule.stack_name}** (${container.Names[0]}):\nMetric \`${rule.metric}\` is \`${currentValue.toFixed(2)}\`, which is \`${rule.operator}\` the threshold of \`${rule.threshold}\`.`
|
||||
message
|
||||
);
|
||||
|
||||
// Update last fired
|
||||
|
||||
@@ -145,7 +145,7 @@ export default function EditorLayout() {
|
||||
|
||||
const fetchNotifications = async () => {
|
||||
try {
|
||||
const res = await apiFetch('/notifications/history');
|
||||
const res = await apiFetch('/notifications');
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
setNotifications(data);
|
||||
|
||||
Reference in New Issue
Block a user