Update various configuration files, components, and assets; enhance notification system and API endpoints; improve documentation and styles across the application.
This commit is contained in:
260
server/api/notifications/logs/monitoring.get.js
Normal file
260
server/api/notifications/logs/monitoring.get.js
Normal file
@@ -0,0 +1,260 @@
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user