260 lines
6.8 KiB
JavaScript
260 lines
6.8 KiB
JavaScript
import prisma from '~/server/utils/prisma'
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
try {
|
|
// Check authentication
|
|
const user = event.context.user;
|
|
if (!user || !user.userID) {
|
|
return {
|
|
statusCode: 401,
|
|
body: { success: false, message: 'Unauthorized' }
|
|
}
|
|
}
|
|
|
|
// Get system status metrics
|
|
const now = new Date()
|
|
const oneDayAgo = new Date(now)
|
|
oneDayAgo.setDate(oneDayAgo.getDate() - 1)
|
|
|
|
// Get total sent in last 24 hours
|
|
const totalSent = await prisma.notification_logs.count({
|
|
where: {
|
|
created_at: {
|
|
gte: oneDayAgo,
|
|
lte: now
|
|
},
|
|
status: 'Sent'
|
|
}
|
|
})
|
|
|
|
// Get success rate in last 24 hours
|
|
const totalAttempted = await prisma.notification_logs.count({
|
|
where: {
|
|
created_at: {
|
|
gte: oneDayAgo,
|
|
lte: now
|
|
},
|
|
action: {
|
|
in: ['Notification Sent', 'Delivery Attempted']
|
|
}
|
|
}
|
|
})
|
|
|
|
const successfulDeliveries = await prisma.notification_logs.count({
|
|
where: {
|
|
created_at: {
|
|
gte: oneDayAgo,
|
|
lte: now
|
|
},
|
|
status: 'Sent'
|
|
}
|
|
})
|
|
|
|
const successRate = totalAttempted > 0
|
|
? ((successfulDeliveries / totalAttempted) * 100).toFixed(2)
|
|
: 0
|
|
|
|
// Get error rate in last 24 hours
|
|
const failedDeliveries = await prisma.notification_logs.count({
|
|
where: {
|
|
created_at: {
|
|
gte: oneDayAgo,
|
|
lte: now
|
|
},
|
|
status: 'Failed'
|
|
}
|
|
})
|
|
|
|
const errorRate = totalAttempted > 0
|
|
? ((failedDeliveries / totalAttempted) * 100).toFixed(2)
|
|
: 0
|
|
|
|
// Get average response time (mock data since we need actual measurements)
|
|
const avgResponseTime = "145"
|
|
|
|
// Calculate status based on metrics
|
|
const getSystemStatus = (metric, thresholds) => {
|
|
if (metric <= thresholds.healthy) return 'healthy'
|
|
if (metric <= thresholds.warning) return 'warning'
|
|
return 'critical'
|
|
}
|
|
|
|
// Get queue status
|
|
const queueStatus = await getQueueStatus(prisma)
|
|
|
|
// Get recent activity
|
|
const recentActivity = await getRecentActivity(prisma)
|
|
|
|
// Get performance metrics
|
|
const performanceMetrics = {
|
|
cpu: 23, // Mock data
|
|
memory: 67, // Mock data
|
|
queueLoad: calculateQueueLoad(queueStatus)
|
|
}
|
|
|
|
// Get error alerts (mock data)
|
|
const errorAlerts = await getErrorAlerts(prisma, oneDayAgo, now)
|
|
|
|
return {
|
|
statusCode: 200,
|
|
body: {
|
|
success: true,
|
|
data: {
|
|
systemStatus: [
|
|
{
|
|
title: "System Health",
|
|
value: errorRate < 1 ? "Healthy" : errorRate < 5 ? "Warning" : "Critical",
|
|
icon: "ic:outline-favorite",
|
|
status: getSystemStatus(errorRate, { healthy: 1, warning: 5 })
|
|
},
|
|
{
|
|
title: "Throughput",
|
|
value: `${Math.round(totalSent / 24)}/hr`,
|
|
icon: "ic:outline-speed",
|
|
status: 'healthy' // Simplified for now
|
|
},
|
|
{
|
|
title: "Error Rate",
|
|
value: `${errorRate}%`,
|
|
icon: "ic:outline-error-outline",
|
|
status: getSystemStatus(errorRate, { healthy: 1, warning: 5 })
|
|
},
|
|
{
|
|
title: "Response Time",
|
|
value: `${avgResponseTime}ms`,
|
|
icon: "ic:outline-timer",
|
|
status: getSystemStatus(parseFloat(avgResponseTime), { healthy: 100, warning: 200 })
|
|
}
|
|
],
|
|
performanceMetrics,
|
|
queueStatus,
|
|
recentActivity,
|
|
errorAlerts
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching monitoring data:', error)
|
|
return {
|
|
statusCode: 500,
|
|
body: { success: false, message: 'Failed to fetch monitoring data', error: error.message }
|
|
}
|
|
}
|
|
})
|
|
|
|
// Helper functions
|
|
async function getQueueStatus(prisma) {
|
|
const channels = ['Email', 'SMS', 'Push Notification', 'Webhook']
|
|
|
|
// In a real implementation, this would query the notification_queue table
|
|
// For now, we'll use mock data
|
|
return [
|
|
{
|
|
name: "Email Queue",
|
|
count: "1,247",
|
|
description: "Pending emails",
|
|
status: "active",
|
|
utilization: 78
|
|
},
|
|
{
|
|
name: "SMS Queue",
|
|
count: "89",
|
|
description: "Pending SMS",
|
|
status: "active",
|
|
utilization: 23
|
|
},
|
|
{
|
|
name: "Push Queue",
|
|
count: "3,456",
|
|
description: "Pending push notifications",
|
|
status: "warning",
|
|
utilization: 92
|
|
},
|
|
{
|
|
name: "Webhook Queue",
|
|
count: "12",
|
|
description: "Pending webhooks",
|
|
status: "active",
|
|
utilization: 8
|
|
}
|
|
]
|
|
}
|
|
|
|
function calculateQueueLoad(queueStatus) {
|
|
// Calculate average utilization across all queues
|
|
const totalUtilization = queueStatus.reduce((sum, queue) => sum + queue.utilization, 0)
|
|
return Math.round(totalUtilization / queueStatus.length)
|
|
}
|
|
|
|
async function getRecentActivity(prisma) {
|
|
// Get the most recent 5 log entries
|
|
const recentLogs = await prisma.notification_logs.findMany({
|
|
orderBy: {
|
|
created_at: 'desc'
|
|
},
|
|
take: 5
|
|
})
|
|
|
|
// Format for the frontend
|
|
return recentLogs.map(log => {
|
|
const timeAgo = formatTimeAgo(log.created_at)
|
|
|
|
return {
|
|
action: log.action,
|
|
description: log.details || 'No details provided',
|
|
status: log.status ? log.status.toLowerCase() : 'unknown',
|
|
time: timeAgo,
|
|
source: log.channel_type || 'System'
|
|
}
|
|
})
|
|
}
|
|
|
|
function formatTimeAgo(timestamp) {
|
|
const now = new Date()
|
|
const time = new Date(timestamp)
|
|
const diffInMinutes = Math.floor((now - time) / (1000 * 60))
|
|
|
|
if (diffInMinutes < 1) return "Just now"
|
|
if (diffInMinutes < 60) return `${diffInMinutes} minutes ago`
|
|
if (diffInMinutes < 1440) return `${Math.floor(diffInMinutes / 60)} hours ago`
|
|
return `${Math.floor(diffInMinutes / 1440)} days ago`
|
|
}
|
|
|
|
async function getErrorAlerts(prisma, startDate, endDate) {
|
|
// Get recent errors
|
|
const recentErrors = await prisma.notification_logs.findMany({
|
|
where: {
|
|
created_at: {
|
|
gte: startDate,
|
|
lte: endDate
|
|
},
|
|
status: 'Failed',
|
|
error_message: {
|
|
not: null
|
|
}
|
|
},
|
|
orderBy: {
|
|
created_at: 'desc'
|
|
},
|
|
take: 3
|
|
})
|
|
|
|
// Format for the frontend
|
|
return recentErrors.map(error => {
|
|
const timeAgo = formatTimeAgo(error.created_at)
|
|
|
|
// Determine severity based on error code or other factors
|
|
let severity = 'warning'
|
|
if (error.error_code && error.error_code.startsWith('CRIT')) {
|
|
severity = 'critical'
|
|
}
|
|
|
|
return {
|
|
title: error.action || 'Error Detected',
|
|
description: error.error_message || 'Unknown error occurred',
|
|
timestamp: timeAgo,
|
|
component: error.channel_type || 'System',
|
|
severity
|
|
}
|
|
})
|
|
}
|