diff --git a/Client/src/Components/Label/index.jsx b/Client/src/Components/Label/index.jsx index 330c6de0a..886f66fb9 100644 --- a/Client/src/Components/Label/index.jsx +++ b/Client/src/Components/Label/index.jsx @@ -126,7 +126,6 @@ ColoredLabel.propTypes = { */ const StatusLabel = ({ status, text, customStyles }) => { - console.log(status); const theme = useTheme(); const colors = { up: { diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 29c0b72e0..f4dd1f64d 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -213,10 +213,11 @@ const PageSpeedDetails = () => { monitorId, "desc", 50, - null, + "day", null, null ); + console.log(res.data.data); setMonitor(res?.data?.data ?? {}); setAudits(res?.data?.data?.checks?.[0]?.audits ?? []); } catch (error) { diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index 6f959f758..29233b73a 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -65,6 +65,7 @@ const { const { getAllMonitors, getMonitorAggregateStats, + testMethod, getMonitorStatsById, getMonitorById, getMonitorsByTeamId, @@ -145,7 +146,6 @@ module.exports = { resetPassword, checkSuperadmin, getAllMonitors, - getMonitorAggregateStats, getMonitorStatsById, getMonitorById, getMonitorsByTeamId, diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js index b913519b6..bfa4bd73a 100644 --- a/Server/db/mongo/modules/monitorModule.js +++ b/Server/db/mongo/modules/monitorModule.js @@ -35,7 +35,7 @@ const calculateUptimeDuration = (checks) => { const latestCheck = new Date(checks[0].createdAt); let latestDownCheck = 0; - for (let i = 0; i < checks.length; i++) { + for (let i = checks.length; i <= 0; i--) { if (checks[i].status === false) { latestDownCheck = new Date(checks[i].createdAt); break; @@ -77,11 +77,11 @@ const getLatestResponseTime = (checks) => { }; /** - * Helper function to get average 24h response time + * Helper function to get average response time * @param {Array} checks Array of check objects. * @returns {number} Timestamp of the most recent check. */ -const getAverageResponseTime24Hours = (checks) => { +const getAverageResponseTime = (checks) => { if (!checks || checks.length === 0) { return 0; } @@ -121,108 +121,6 @@ const getIncidents = (checks) => { return check.status === false ? (acc += 1) : acc; }, 0); }; -/** - * Helper function to get all incidents - * @param {Array} checks Array of check objects. - * @returns {Array} Array of booleans representing up/down. - */ -const getStatusBarValues = (monitor, checks) => { - const checksIn60Mins = Math.floor((60 * 60 * 1000) / monitor.interval); - const noBlankChecks = checksIn60Mins - checks.length; - - const statusBarValues = checks.map((check) => { - return { - status: check.status, - responseTime: check.responseTime, - value: 75, - }; - }); - - for (let i = 0; i < noBlankChecks; i++) { - statusBarValues.push({ status: undefined, responseTime: 0, value: 75 }); - } - return statusBarValues.reverse(); -}; - -/** - * Get aggregate monitor stats for charts - * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - * @throws {Error} - */ -const getMonitorAggregateStats = async (monitorId, dateRange) => { - const startDates = { - day: new Date(new Date().setDate(new Date().getDate() - 1)), - week: new Date(new Date().setDate(new Date().getDate() - 7)), - month: new Date(new Date().setMonth(new Date().getMonth() - 1)), - }; - - try { - const startDate = startDates[dateRange]; - if (!startDate) { - throw new Error("Invalid date range specified"); - } - const endDate = new Date(); - - const checks = await Check.find({ - monitorId: monitorId, - createdAt: { - $gte: startDate, - $lte: endDate, - }, - }); - - let groupedChecks; - // Group checks by hour if range is day - if (dateRange === "day") { - groupedChecks = checks.reduce((acc, check) => { - const hour = new Date(check.createdAt).getHours(); - if (!acc[hour]) { - acc[hour] = { hour, checks: [] }; - } - acc[hour].checks.push(check); - return acc; - }, {}); - } - - // Group checks by day if range is week or month - else { - groupedChecks = checks.reduce((acc, check) => { - const day = new Date(check.createdAt).toISOString().split("T")[0]; // Extract the date part - if (!acc[day]) { - acc[day] = { day, checks: [] }; - } - acc[day].checks.push(check); - return acc; - }, {}); - } - - // Map grouped checks to stats - stats = Object.values(groupedChecks).map((group) => { - const totalChecks = group.checks.length; - const totalIncidents = group.checks.filter( - (check) => check.status === false - ).length; - const avgResponseTime = - group.checks.reduce((sum, check) => sum + check.responseTime, 0) / - totalChecks; - - return { - hour: group.hour, - day: group.day, - totalChecks, - totalIncidents, - avgResponseTime, - }; - }); - - return stats; - } catch (error) { - throw error; - } -}; /** * Get stats by monitor ID @@ -233,42 +131,35 @@ const getMonitorAggregateStats = async (monitorId, dateRange) => { * @throws {Error} */ const getMonitorStatsById = async (req) => { - const filterLookup = { - hour: new Date(new Date().getTime() - 60 * 60 * 1000), + const startDates = { day: new Date(new Date().setDate(new Date().getDate() - 1)), week: new Date(new Date().setDate(new Date().getDate() - 7)), month: new Date(new Date().setMonth(new Date().getMonth() - 1)), }; - + const endDate = new Date(); try { - const { monitorId } = req.params; - let { status, limit, sortOrder, dateRange, numToDisplay, normalize } = - req.query; - - // This effectively removes limit, returning all checks - if (limit === undefined) limit = 0; - - // Default sort order is newest -> oldest - sortOrder = sortOrder === "asc" ? 1 : -1; - // Get monitor + const { monitorId } = req.params; + let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query; const monitor = await Monitor.findById(monitorId); if (monitor === null || monitor === undefined) { throw new Error(errorMessages.DB_FIND_MONTIOR_BY_ID(monitorId)); } + // This effectively removes limit, returning all checks + if (limit === undefined) limit = 0; + // Default sort order is newest -> oldest + sortOrder = sortOrder === "asc" ? 1 : -1; - // Determine if this is a pagespeed monitor or an http/ping monitor let model = monitor.type === "http" || monitor.type === "ping" ? Check : PageSpeedCheck; - // Build monitor stats object const monitorStats = { ...monitor.toObject(), }; - // Start building query + // Build checks query const checksQuery = { monitorId: monitor._id }; // Get all checks @@ -276,83 +167,101 @@ const getMonitorStatsById = async (req) => { createdAt: sortOrder, }); + const checksQueryForDateRange = { + ...checksQuery, + createdAt: { + $gte: startDates[dateRange], + $lte: endDate, + }, + }; + + const checksForDateRange = await model + .find(checksQueryForDateRange) + .sort({ createdAt: sortOrder }); + if (monitor.type === "http" || monitor.type === "ping") { - const checksQuery24Hours = { - ...checksQuery, - createdAt: { $gte: filterLookup.day }, - }; - const checksQuery7Days = { - ...checksQuery, - createdAt: { $gte: filterLookup.week }, - }; - const checksQuery30Days = { - ...checksQuery, - createdAt: { $gte: filterLookup.month }, - }; - const checksQuery60Mins = { - ...checksQuery, - createdAt: { $gte: filterLookup.hour }, - }; - - const [checks24Hours, checks7Days, checks30Days, checks60Mins] = - await Promise.all([ - model.find(checksQuery24Hours).sort({ createdAt: sortOrder }), - model.find(checksQuery7Days).sort({ createdAt: sortOrder }), - model.find(checksQuery30Days).sort({ createdAt: sortOrder }), - model.find(checksQuery60Mins).sort({ createdAt: sortOrder }), - ]); - // HTTP/PING Specific stats - monitorStats.avgResponseTime24hours = - getAverageResponseTime24Hours(checks24Hours); - monitorStats.uptime7Days = getUptimePercentage(checks7Days); - monitorStats.uptime24Hours = getUptimePercentage(checks24Hours); - monitorStats.uptime30Days = getUptimePercentage(checks30Days); - monitorStats.statusBar = getStatusBarValues(monitor, checks60Mins); + monitorStats.periodAvgResponseTime = + getAverageResponseTime(checksForDateRange); + monitorStats.periodUptime = getUptimePercentage(checksForDateRange); + + // Aggregate data + let groupedChecks; + // Group checks by hour if range is day + if (dateRange === "day") { + groupedChecks = checksForDateRange.reduce((acc, check) => { + const time = new Date(check.createdAt); + time.setMinutes(0, 0, 0); + if (!acc[time]) { + acc[time] = { time, checks: [] }; + } + acc[time].checks.push(check); + return acc; + }, {}); + } else { + groupedChecks = checksForDateRange.reduce((acc, check) => { + const time = new Date(check.createdAt).toISOString().split("T")[0]; // Extract the date part + if (!acc[time]) { + acc[time] = { time, checks: [] }; + } + acc[time].checks.push(check); + return acc; + }, {}); + } + + // Map grouped checks to stats + const aggregateData = Object.values(groupedChecks).map((group) => { + const totalChecks = group.checks.length; + const uptimePercentage = getUptimePercentage(group.checks); + const totalIncidents = group.checks.filter( + (check) => check.status === false + ).length; + const avgResponseTime = + group.checks.reduce((sum, check) => sum + check.responseTime, 0) / + totalChecks; + + return { + time: group.time, + uptimePercentage, + totalChecks, + totalIncidents, + avgResponseTime, + }; + }); + monitorStats.aggregateData = aggregateData; } - //Get checks for dateRange - if (status !== undefined) { - checksQuery.status = status; - } - - // Filter checks by "day", "week", or "month" - if (dateRange !== undefined) { - checksQuery.createdAt = { $gte: filterLookup[dateRange] }; - } - - let dateRangeChecks = await model - .find(checksQuery) - .sort({ - createdAt: sortOrder, - }) - .limit(limit); - - const incidents = getIncidents(dateRangeChecks); + monitorStats.periodIncidents = getIncidents(checksForDateRange); + monitorStats.periodTotalChecks = checksForDateRange.length; // If more than numToDisplay checks, pick every nth check + + let nthChecks = checksForDateRange; + if ( numToDisplay !== undefined && - dateRangeChecks && - dateRangeChecks.length > numToDisplay + checksForDateRange && + checksForDateRange.length > numToDisplay ) { - const n = Math.ceil(dateRangeChecks.length / numToDisplay); - dateRangeChecks = dateRangeChecks.filter((_, index) => index % n === 0); + const n = Math.ceil(checksForDateRange.length / numToDisplay); + nthChecks = checksForDateRange.filter((_, index) => index % n === 0); } // Normalize checks if requested if (normalize !== undefined) { - dateRangeChecks = NormalizeData(dateRangeChecks, 1, 100); + const normailzedChecks = NormalizeData(nthChecks, 1, 100); + monitorStats.checks = normailzedChecks; + } else { + monitorStats.checks = nthChecks; } - // Add common stats and stats that depend on the dateRange monitorStats.uptimeDuration = calculateUptimeDuration(checksAll); monitorStats.lastChecked = getLastChecked(checksAll); monitorStats.latestResponseTime = getLatestResponseTime(checksAll); - monitorStats.incidents = incidents; - monitorStats.checks = dateRangeChecks; + return monitorStats; } catch (error) { + error.methodName = "getMonitorStatsById"; throw error; } }; @@ -540,7 +449,6 @@ const editMonitor = async (candidateId, candidateMonitor) => { module.exports = { getAllMonitors, - getMonitorAggregateStats, getMonitorStatsById, getMonitorById, getMonitorsByTeamId, diff --git a/Server/middleware/handleErrors.js b/Server/middleware/handleErrors.js index 1e1e955c5..db51c1af6 100644 --- a/Server/middleware/handleErrors.js +++ b/Server/middleware/handleErrors.js @@ -5,7 +5,10 @@ const handleErrors = (error, req, res, next) => { const status = error.status || 500; const message = error.message || errorMessages.FRIENDLY_ERROR; const service = error.service || errorMessages.UNKNOWN_SERVICE; - logger.error(error.message, { service: service }); + logger.error(error.message, { + service: service, + methodName: error.methodName, + }); res.status(status).json({ success: false, msg: message }); }; diff --git a/Server/service/networkService.js b/Server/service/networkService.js index 863349dbf..e25a63ce5 100644 --- a/Server/service/networkService.js +++ b/Server/service/networkService.js @@ -197,7 +197,6 @@ class NetworkService { */ async handlePagespeed(job) { let isAlive; - try { const url = job.data.url; const response = await axios.get(