From 397c87b31883ef112f5bb52772a363a6c9cf127d Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Thu, 27 Mar 2025 02:12:33 +0530 Subject: [PATCH 01/11] fix: minor redirect added --- frontend/src/components/HighlightedCard.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/src/components/HighlightedCard.jsx b/frontend/src/components/HighlightedCard.jsx index 940b5fd2..7b655cf8 100644 --- a/frontend/src/components/HighlightedCard.jsx +++ b/frontend/src/components/HighlightedCard.jsx @@ -7,10 +7,13 @@ import ChevronRightRoundedIcon from "@mui/icons-material/ChevronRightRounded"; import InsightsRoundedIcon from "@mui/icons-material/InsightsRounded"; import useMediaQuery from "@mui/material/useMediaQuery"; import { useTheme } from "@mui/material/styles"; +import { useRecoilState } from "recoil"; +import { activeViewState } from "../utils/state"; export default function HighlightedCard() { const theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down("sm")); + const [_, setActiveViewState] = useRecoilState(activeViewState); return ( @@ -33,6 +36,9 @@ export default function HighlightedCard() { color="primary" endIcon={} fullWidth={isSmallScreen} + onClick={() => { + setActiveViewState("chat"); + }} > Get insights From 61a08e60ca3b4d4f433422e19b45f403efc9ef54 Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Sun, 9 Mar 2025 23:25:52 +0530 Subject: [PATCH 02/11] feat: adds stats route to generate stats of last 180 days --- backend/src/index.ts | 2 + backend/src/routes/getStats.ts | 175 +++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 backend/src/routes/getStats.ts diff --git a/backend/src/index.ts b/backend/src/index.ts index 5206dc4e..198c2186 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -3,6 +3,7 @@ import cors from 'cors'; import dotenv from 'dotenv'; import uploadRoutes from './routes/upload'; import allLogs from './routes/getAllLogs'; +import getStats from './routes/getStats'; import connectToDatabase from './db/connect'; dotenv.config(); @@ -24,6 +25,7 @@ app.get('/', (req: Request, res: Response): void => { app.use('/api', uploadRoutes); app.use('/api', allLogs); +app.use('/api', getStats) app.listen(PORT, (): void => { console.log(`Server is running on http://localhost:${PORT}`); diff --git a/backend/src/routes/getStats.ts b/backend/src/routes/getStats.ts new file mode 100644 index 00000000..c363a9b8 --- /dev/null +++ b/backend/src/routes/getStats.ts @@ -0,0 +1,175 @@ +import express from 'express'; +import { Request, Response } from 'express'; +import { LinuxLogModel } from '../models/LinuxLogModel'; + +const router = express.Router(); + +router.get('/stats', async (req: Request, res: Response) => { + try { + const startDate = new Date(); + startDate.setDate(startDate.getDate() - 180); // 180 days ago + + const totalLogsAgg = await LinuxLogModel.aggregate([ + { + $match: { timestamp: { $gte: startDate } } + }, + { + $group: { + _id: { + year: { $year: '$timestamp' }, + month: { $month: '$timestamp' }, + day: { $dayOfMonth: '$timestamp' }, + }, + count: { $sum: 1 }, + } + }, + { + $sort: { + "_id.year": 1, + "_id.month": 1, + "_id.day": 1, + } + } + ]); + + const errorLogsAgg = await LinuxLogModel.aggregate([ + { + $match: { + timestamp: { $gte: startDate }, + severity: { $in: ['ERROR'] } + }, + }, + { + $group: { + _id: { + year: { $year: '$timestamp' }, + month: { $month: '$timestamp' }, + day: { $dayOfMonth: '$timestamp' }, + }, + count: { $sum: 1 }, + } + }, + { + $sort: { + "_id.year": 1, + "_id.month": 1, + "_id.day": 1, + } + } + ]); + + const warningLogsAgg = await LinuxLogModel.aggregate([ + { + $match: { + timestamp: { $gte: startDate }, + severity: { $in: ['WARNING'] } // Adjust this based on your severity levels + }, + }, + { + $group: { + _id: { + year: { $year: '$timestamp' }, + month: { $month: '$timestamp' }, + day: { $dayOfMonth: '$timestamp' }, + }, + count: { $sum: 1 }, + } + }, + { + $sort: { + "_id.year": 1, + "_id.month": 1, + "_id.day": 1, + } + } + ]); + + + // Format Helper to build a 180 days array + const totalLogsData = buildDailyArray(totalLogsAgg, startDate); + const errorLogsData = buildDailyArray(errorLogsAgg, startDate); + const warningLogsData = buildDailyArray(warningLogsAgg, startDate); + + // sum up total logs + const totalLogsSum = totalLogsData.reduce((acc, count) => acc + count, 0); + const errorLogsSum = errorLogsData.reduce((acc, count) => acc + count, 0); + const warningLogsSum = warningLogsData.reduce((acc, count) => acc + count, 0); + + //compute tends + const totalLogsTend = computeTrend(totalLogsData); + const errorLogsTend = computeTrend(errorLogsData); + const warningLogsTend = computeTrend(warningLogsData); + + res.json([ + { + title: "Total Logs", + value: totalLogsSum, // e.g. "14k" or a number + interval: "Last 180 days", + trend: totalLogsTend, // "up", "down", or "neutral" + data: totalLogsData, // [0, 3, 5, 2, ...] for 180 days + }, + { + title: "Error Count", + value: errorLogsSum, + interval: "Last 180 days", + trend: errorLogsTend, + data: errorLogsData, + }, + { + title: "Warning Count", + value: warningLogsSum, + interval: "Last 180 days", + trend: warningLogsTend, + data: warningLogsData, + }, + ]) + + + + } catch (error) { + console.error(error); + res.status(500).json({ error: "Something went wrong." }); + } +}); + +function buildDailyArray( + aggResults: { _id: { year: number; month: number; day: number }; count: number }[], + startDate: Date +): number[] { + const daysCount = 180; + const dailyArray = new Array(daysCount).fill(0); + + for (const doc of aggResults) { + const { year, month, day } = doc._id; + const thisDate = new Date(year, month - 1, day); // month is 0-indexed in JS + const index = Math.floor((thisDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)); + + if (index >= 0 && index < daysCount) { + dailyArray[index] = doc.count; + } + } + + return dailyArray; +} + + +function computeTrend(data: number[]) { + if (data.length < 2) return "neutral"; + + const recentValue = data[data.length - 1]; + const previousValue = data[data.length - 2]; + + if (recentValue > previousValue) { + return "up"; + } else if (recentValue < previousValue) { + return "down"; + } else { + return "neutral"; + } +} + + +export default router; + + + From 124f34585887f326fc76992c0e590546cff50403 Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Sun, 9 Mar 2025 23:28:03 +0530 Subject: [PATCH 03/11] feat: adds stats route to generate stats of last 90 days --- backend/src/routes/getStats.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/src/routes/getStats.ts b/backend/src/routes/getStats.ts index c363a9b8..00d01487 100644 --- a/backend/src/routes/getStats.ts +++ b/backend/src/routes/getStats.ts @@ -7,7 +7,7 @@ const router = express.Router(); router.get('/stats', async (req: Request, res: Response) => { try { const startDate = new Date(); - startDate.setDate(startDate.getDate() - 180); // 180 days ago + startDate.setDate(startDate.getDate() - 90); // 90 days ago const totalLogsAgg = await LinuxLogModel.aggregate([ { @@ -104,21 +104,21 @@ router.get('/stats', async (req: Request, res: Response) => { { title: "Total Logs", value: totalLogsSum, // e.g. "14k" or a number - interval: "Last 180 days", + interval: "Last 90 days", trend: totalLogsTend, // "up", "down", or "neutral" data: totalLogsData, // [0, 3, 5, 2, ...] for 180 days }, { title: "Error Count", value: errorLogsSum, - interval: "Last 180 days", + interval: "Last 90 days", trend: errorLogsTend, data: errorLogsData, }, { title: "Warning Count", value: warningLogsSum, - interval: "Last 180 days", + interval: "Last 90 days", trend: warningLogsTend, data: warningLogsData, }, @@ -141,7 +141,7 @@ function buildDailyArray( for (const doc of aggResults) { const { year, month, day } = doc._id; - const thisDate = new Date(year, month - 1, day); // month is 0-indexed in JS + const thisDate = new Date(year, month - 1, day); // month is 0-indexed const index = Math.floor((thisDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)); if (index >= 0 && index < daysCount) { From 552826aa051da5db33100f71099b4e93dd8dfe83 Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Sun, 9 Mar 2025 23:58:41 +0530 Subject: [PATCH 04/11] fix: fixes more issuee --- backend/src/routes/getStats.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/src/routes/getStats.ts b/backend/src/routes/getStats.ts index 00d01487..9084ff80 100644 --- a/backend/src/routes/getStats.ts +++ b/backend/src/routes/getStats.ts @@ -85,7 +85,7 @@ router.get('/stats', async (req: Request, res: Response) => { ]); - // Format Helper to build a 180 days array + // Format Helper to build a 90 days array const totalLogsData = buildDailyArray(totalLogsAgg, startDate); const errorLogsData = buildDailyArray(errorLogsAgg, startDate); const warningLogsData = buildDailyArray(warningLogsAgg, startDate); @@ -100,6 +100,8 @@ router.get('/stats', async (req: Request, res: Response) => { const errorLogsTend = computeTrend(errorLogsData); const warningLogsTend = computeTrend(warningLogsData); + + res.json([ { title: "Total Logs", @@ -136,7 +138,7 @@ function buildDailyArray( aggResults: { _id: { year: number; month: number; day: number }; count: number }[], startDate: Date ): number[] { - const daysCount = 180; + const daysCount = 90; const dailyArray = new Array(daysCount).fill(0); for (const doc of aggResults) { From bf218ae374e3adee2f6f8fae2f9a864b96e0b9fd Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Fri, 28 Mar 2025 00:08:54 +0530 Subject: [PATCH 05/11] add: adds sampel demo chat page --- frontend/package-lock.json | 4 +- frontend/package.json | 1 - frontend/src/components/Chat.jsx | 87 ++++++++++++++++++- frontend/src/components/PageViewsBarChart.jsx | 83 ------------------ 4 files changed, 85 insertions(+), 90 deletions(-) delete mode 100644 frontend/src/components/PageViewsBarChart.jsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3da335e0..f8040678 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -26,7 +26,6 @@ "@react-spring/web": "^9.7.5", "d3": "^7.9.0", "dayjs": "^1.11.13", - "leaflet": "^1.9.4", "lucide-react": "^0.485.0", "react": "^18.0.0", "react-dom": "^18.0.0", @@ -4198,7 +4197,8 @@ "version": "1.9.4", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", - "license": "BSD-2-Clause" + "license": "BSD-2-Clause", + "peer": true }, "node_modules/levn": { "version": "0.4.1", diff --git a/frontend/package.json b/frontend/package.json index 9982b006..063dd9ed 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,7 +28,6 @@ "@react-spring/web": "^9.7.5", "d3": "^7.9.0", "dayjs": "^1.11.13", - "leaflet": "^1.9.4", "lucide-react": "^0.485.0", "react": "^18.0.0", "react-dom": "^18.0.0", diff --git a/frontend/src/components/Chat.jsx b/frontend/src/components/Chat.jsx index e3b43164..7fa4058e 100644 --- a/frontend/src/components/Chat.jsx +++ b/frontend/src/components/Chat.jsx @@ -1,17 +1,96 @@ -import { Stack } from "@mui/material"; +import { + Box, + IconButton, + Paper, + Stack, + TextField, + Typography, +} from "@mui/material"; +import SendIcon from "@mui/icons-material/Send"; +import { useEffect, useRef, useState } from "react"; export default function Chat() { + const [messages, setMessages] = useState([ + { id: 1, text: "Hello, how can I help you?", sender: "bot" }, + { id: 2, text: "I need help analyzing my logs", sender: "user" }, + ]); + const [newMessage, setNewMessage] = useState(""); + const messagesEndRef = useRef(null); + + const handleSend = () => { + if (newMessage.trim()) { + setMessages([ + ...messages, + { id: messages.length + 1, text: newMessage, sender: "user" }, + ]); + setNewMessage(""); + } + }; + + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages]); + return ( -

Chat

+ + {messages.map((message) => ( + + + {message.text} + + + ))} +
+ + + + setNewMessage(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && handleSend()} + /> + + + + ); } diff --git a/frontend/src/components/PageViewsBarChart.jsx b/frontend/src/components/PageViewsBarChart.jsx deleted file mode 100644 index b3457522..00000000 --- a/frontend/src/components/PageViewsBarChart.jsx +++ /dev/null @@ -1,83 +0,0 @@ -import * as React from "react"; -import Card from "@mui/material/Card"; -import CardContent from "@mui/material/CardContent"; -import Chip from "@mui/material/Chip"; -import Typography from "@mui/material/Typography"; -import Stack from "@mui/material/Stack"; -import { BarChart } from "@mui/x-charts/BarChart"; -import { useTheme } from "@mui/material/styles"; - -export default function PageViewsBarChart() { - const theme = useTheme(); - const colorPalette = [ - (theme.vars || theme).palette.primary.dark, - (theme.vars || theme).palette.primary.main, - (theme.vars || theme).palette.primary.light, - ]; - return ( - - - - Analyzed Logs - - - - - 12K - - - - - Logs analyzed in the last 30 days - - - - - - ); -} From cff978d0ad9b7eb365d56ca476fd718176bbe46a Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Fri, 28 Mar 2025 00:09:44 +0530 Subject: [PATCH 06/11] feat: adds featch stats data from backend to display --- .../src/components/LogAnalyzedBarGraph.jsx | 83 +++++++++++++++++++ frontend/src/components/MainGrid.jsx | 56 +++++-------- frontend/src/components/StatCard.jsx | 28 ++++--- frontend/src/utils/api/fetchStats.js | 13 +++ 4 files changed, 132 insertions(+), 48 deletions(-) create mode 100644 frontend/src/components/LogAnalyzedBarGraph.jsx create mode 100644 frontend/src/utils/api/fetchStats.js diff --git a/frontend/src/components/LogAnalyzedBarGraph.jsx b/frontend/src/components/LogAnalyzedBarGraph.jsx new file mode 100644 index 00000000..bec8cec3 --- /dev/null +++ b/frontend/src/components/LogAnalyzedBarGraph.jsx @@ -0,0 +1,83 @@ +import * as React from "react"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import Chip from "@mui/material/Chip"; +import Typography from "@mui/material/Typography"; +import Stack from "@mui/material/Stack"; +import { BarChart } from "@mui/x-charts/BarChart"; +import { useTheme } from "@mui/material/styles"; + +export default function LogAnalyzedBarChart() { + const theme = useTheme(); + const colorPalette = [ + (theme.vars || theme).palette.primary.dark, + (theme.vars || theme).palette.primary.main, + (theme.vars || theme).palette.primary.light, + ]; + return ( + + + + Analyzed Logs + + + + + 12K + + + + + Logs analyzed in the last 30 days + + + + + + ); +} diff --git a/frontend/src/components/MainGrid.jsx b/frontend/src/components/MainGrid.jsx index bdb66f7a..1cb90bf9 100644 --- a/frontend/src/components/MainGrid.jsx +++ b/frontend/src/components/MainGrid.jsx @@ -5,45 +5,29 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; import LogTypeStatus from "./LogTypeStatus"; import HighlightedCard from "./HighlightedCard"; -import PageViewsBarChart from "./PageViewsBarChart"; +import LogAnalyzedBarChart from "./LogAnalyzedBarGraph"; import SessionsChart from "./SessionsChart"; import StatCard from "./StatCard"; - -const data = [ - { - title: "Total Logs", - value: "14k", - interval: "Last 30 days", - trend: "up", - data: [ - 200, 24, 220, 260, 240, 380, 100, 240, 280, 240, 300, 340, 320, 360, 340, - 380, 360, 400, 380, 420, 400, 640, 340, 460, 440, 480, 460, 600, 880, 920, - ], - }, - { - title: "Error Count", - value: "1.2k", - interval: "Last 30 days", - trend: "down", - data: [ - 1640, 1250, 970, 1130, 1050, 900, 720, 1080, 900, 450, 920, 820, 840, 600, - 820, 780, 800, 760, 380, 740, 660, 620, 840, 500, 520, 480, 400, 360, 300, - 220, - ], - }, - { - title: "Warning Count", - value: "2.5k", - interval: "Last 30 days", - trend: "neutral", - data: [ - 500, 400, 510, 530, 520, 600, 530, 520, 510, 730, 520, 510, 530, 620, 510, - 530, 520, 410, 530, 520, 610, 530, 520, 610, 530, 420, 510, 430, 520, 510, - ], - }, -]; +import fetchStats from "../utils/api/fetchStats"; +import { useState, useEffect } from "react"; export default function MainGrid() { + const [data, setData] = useState([]); + const [loading, setLoading] = useState(true); + useEffect(() => { + const fetchData = async () => { + try { + const response = await fetchStats(); + setData(response); + } catch (error) { + console.error("Error fetching data:", error); + } finally { + setLoading(false); + } + }; + fetchData(); + }, []); + if (loading) return
Loading...
; return ( {/* cards */} @@ -68,7 +52,7 @@ export default function MainGrid() { - + diff --git a/frontend/src/components/StatCard.jsx b/frontend/src/components/StatCard.jsx index ab804e5e..9f672013 100644 --- a/frontend/src/components/StatCard.jsx +++ b/frontend/src/components/StatCard.jsx @@ -9,18 +9,23 @@ import Typography from "@mui/material/Typography"; import { SparkLineChart } from "@mui/x-charts/SparkLineChart"; import { areaElementClasses } from "@mui/x-charts/LineChart"; -function getDaysInMonth(month, year) { - const date = new Date(year, month, 0); - const monthName = date.toLocaleDateString("en-US", { - month: "short", - }); - const daysInMonth = date.getDate(); +function getDaysInMonth() { + // Create an array of 90 days from today const days = []; - let i = 1; - while (days.length < daysInMonth) { - days.push(`${monthName} ${i}`); - i += 1; + const startDate = new Date(); + + for (let i = 0; i < 90; i++) { + const currentDate = new Date(startDate); + currentDate.setDate(startDate.getDate() + i); + + const monthName = currentDate.toLocaleDateString("en-US", { + month: "short", + }); + const dayOfMonth = currentDate.getDate(); + + days.push(`${monthName} ${dayOfMonth}`); } + return days; } @@ -37,8 +42,7 @@ function AreaGradient({ color, id }) { export default function StatCard({ title, value, interval, trend, data }) { const theme = useTheme(); - const daysInWeek = getDaysInMonth(4, 2024); - + const daysInWeek = getDaysInMonth(); const trendColors = { up: theme.palette.mode === "light" diff --git a/frontend/src/utils/api/fetchStats.js b/frontend/src/utils/api/fetchStats.js new file mode 100644 index 00000000..92b46b73 --- /dev/null +++ b/frontend/src/utils/api/fetchStats.js @@ -0,0 +1,13 @@ +export default async function fetchStats() { + const data = await fetch(`${import.meta.env.VITE_BACKEND_URL}/api/stats`) + + if(!data.ok) { + throw new Error("Network response was not ok" + data.statusText); + } + + const dataJson = await data.json(); + if (!dataJson) { + throw new Error("No data found"); + } + return dataJson; +} From b641edc3e4a6f1efc0c37a96dc2b41add468b5da Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Sun, 9 Mar 2025 00:36:59 +0530 Subject: [PATCH 07/11] feat: adds log type status route and function --- backend/src/index.ts | 2 ++ backend/src/routes/logTypeStatus.ts | 47 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 backend/src/routes/logTypeStatus.ts diff --git a/backend/src/index.ts b/backend/src/index.ts index 198c2186..2da1aed8 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -4,6 +4,7 @@ import dotenv from 'dotenv'; import uploadRoutes from './routes/upload'; import allLogs from './routes/getAllLogs'; import getStats from './routes/getStats'; +import logtypeStatus from './routes/logTypeStatus'; import connectToDatabase from './db/connect'; dotenv.config(); @@ -26,6 +27,7 @@ app.get('/', (req: Request, res: Response): void => { app.use('/api', uploadRoutes); app.use('/api', allLogs); app.use('/api', getStats) +app.use('/api', logtypeStatus) app.listen(PORT, (): void => { console.log(`Server is running on http://localhost:${PORT}`); diff --git a/backend/src/routes/logTypeStatus.ts b/backend/src/routes/logTypeStatus.ts new file mode 100644 index 00000000..5fc341f7 --- /dev/null +++ b/backend/src/routes/logTypeStatus.ts @@ -0,0 +1,47 @@ +import express from 'express'; +import { Request, Response } from 'express'; +import { LinuxLogModel } from '../models/LinuxLogModel'; + +const router = express.Router(); + +router.get('/logtypeStatus', async (req: Request, res: Response) => { + try { + /* + const data = [ + { label: "SYSLOG", value: 50000 }, + { label: "WINDOWLOG", value: 35000 }, + { label: "AUTHLOG", value: 10000 }, + { label: "KERNEL", value: 10000 }, + { label: "UNKNOWN", value: 5000 }, +]; + */ + + const syslogCount = await LinuxLogModel.countDocuments({ logType: 'SYSLOG' }); + const windowlogCount = await LinuxLogModel.countDocuments({ logType: 'WINDOWLOG' }); + const authlogCount = await LinuxLogModel.countDocuments({ logType: 'AUTH' }); + const kernelCount = await LinuxLogModel.countDocuments({ logType: 'KERNEL' }); + const unknownCount = await LinuxLogModel.countDocuments({ logType: { $regex: 'UNKNOWN' } }); + + const data = [ + { label: "SYSLOG", value: syslogCount }, + { label: "WINDOWLOG", value: windowlogCount }, + { label: "AUTHLOG", value: authlogCount }, + { label: "KERNEL", value: kernelCount }, + { label: "UNKNOWN", value: unknownCount }, + ]; + + res.json(data); + + + } catch (error) { + console.error(error); + res.status(500).json({ error: "Something went wrong." }); + } +}); + + + +export default router; + + + From d1a7d6e7bc33b4418c3baf806145727aa964d7ca Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Fri, 28 Mar 2025 00:37:44 +0530 Subject: [PATCH 08/11] feat: completes log type status and fetch work on frontend --- frontend/src/components/LogTypeStatus.jsx | 101 +++++++++++++--------- frontend/src/utils/api/logtypeStatus.js | 13 +++ 2 files changed, 72 insertions(+), 42 deletions(-) create mode 100644 frontend/src/utils/api/logtypeStatus.js diff --git a/frontend/src/components/LogTypeStatus.jsx b/frontend/src/components/LogTypeStatus.jsx index 264fc532..6496340d 100644 --- a/frontend/src/components/LogTypeStatus.jsx +++ b/frontend/src/components/LogTypeStatus.jsx @@ -15,47 +15,15 @@ import System from "@mui/icons-material/Computer"; import Window from "@mui/icons-material/Window"; import Kernel from "@mui/icons-material/Memory"; import Auth from "@mui/icons-material/LockOpen"; +import logtypeStatus from "../utils/api/logtypeStatus"; -const data = [ - { label: "SYSLOG", value: 50000 }, - { label: "WINDOWLOG", value: 35000 }, - { label: "AUTHLOG", value: 10000 }, - { label: "KERNEL", value: 10000 }, - { label: "UNKNOWN", value: 5000 }, -]; - -const countries = [ - { - name: "SYSLOG", - value: 50, - flag: , - color: "hsl(220, 25%, 65%)", - }, - { - name: "WINDOWLOG", - value: 35, - flag: , - color: "hsl(220, 25%, 45%)", - }, - { - name: "AUTHLOG", - value: 10, - flag: , - color: "hsl(220, 25%, 30%)", - }, - { - name: "KERNEL", - value: 10, - flag: , - color: "hsl(220, 25%, 30%)", - }, - { - name: "UNKNOWN", - value: 5, - flag: , - color: "hsl(220, 25%, 20%)", - }, -]; +// const data = [ +// { label: "SYSLOG", value: 50000 }, +// { label: "WINDOWLOG", value: 35000 }, +// { label: "AUTHLOG", value: 10000 }, +// { label: "KERNEL", value: 10000 }, +// { label: "UNKNOWN", value: 5000 }, +// ]; const StyledText = styled("text", { shouldForwardProp: (prop) => prop !== "variant", @@ -120,6 +88,55 @@ const colors = [ ]; export default function LogTypeStatus() { + const [data, setData] = React.useState([]); + const [totalCount, setTotalCount] = React.useState("0"); + const [loading, setLoading] = React.useState(true); + + React.useEffect(() => { + const fetchData = async () => { + try { + const response = await logtypeStatus(); + console.log("LogTypeStatus response:", response); + setData(response); + + //convert to string with the K notation + const total = response.reduce((acc, item) => acc + item.value, 0); + const totalString = + total >= 1000 ? `${(total / 1000).toFixed(1)}K` : total.toString(); + setTotalCount(totalString); + } catch (error) { + console.error("Error fetching data:", error); + } finally { + setLoading(false); + } + }; + fetchData(); + }, []); + const total = data.reduce((acc, item) => acc + item.value, 0); + + const iconMap = { + SYSLOG: { flag: , color: "hsl(220, 25%, 65%)" }, + WINDOWLOG: { flag: , color: "hsl(220, 25%, 45%)" }, + AUTHLOG: { flag: , color: "hsl(220, 25%, 30%)" }, + KERNEL: { flag: , color: "hsl(220, 25%, 30%)" }, + UNKNOWN: { flag: , color: "hsl(220, 25%, 20%)" }, + }; + + const logData = data.map((item) => { + const percentage = total > 0 ? Math.round((item.value / total) * 100) : 0; + const defaultIcon = { flag: , color: "hsl(220, 25%, 20%)" }; + const { flag, color } = iconMap[item.label] || defaultIcon; + + return { + name: item.label, + value: percentage, + flag, + color, + rawValue: item.value, + }; + }); + + if (loading) return
Loading...
; return ( - +
- {countries.map((country, index) => ( + {logData.map((country, index) => ( Date: Mon, 10 Mar 2025 01:07:50 +0530 Subject: [PATCH 09/11] feat: adds log severity status route and function --- backend/src/index.ts | 2 + backend/src/routes/logTypeStatus.ts | 10 ---- backend/src/routes/severityInfo.ts | 74 +++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 backend/src/routes/severityInfo.ts diff --git a/backend/src/index.ts b/backend/src/index.ts index 2da1aed8..f4e584f6 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -6,6 +6,7 @@ import allLogs from './routes/getAllLogs'; import getStats from './routes/getStats'; import logtypeStatus from './routes/logTypeStatus'; import connectToDatabase from './db/connect'; +import severityInfo from './routes/severityInfo'; dotenv.config(); @@ -28,6 +29,7 @@ app.use('/api', uploadRoutes); app.use('/api', allLogs); app.use('/api', getStats) app.use('/api', logtypeStatus) +app.use('/api', severityInfo) app.listen(PORT, (): void => { console.log(`Server is running on http://localhost:${PORT}`); diff --git a/backend/src/routes/logTypeStatus.ts b/backend/src/routes/logTypeStatus.ts index 5fc341f7..0531b5ca 100644 --- a/backend/src/routes/logTypeStatus.ts +++ b/backend/src/routes/logTypeStatus.ts @@ -6,16 +6,6 @@ const router = express.Router(); router.get('/logtypeStatus', async (req: Request, res: Response) => { try { - /* - const data = [ - { label: "SYSLOG", value: 50000 }, - { label: "WINDOWLOG", value: 35000 }, - { label: "AUTHLOG", value: 10000 }, - { label: "KERNEL", value: 10000 }, - { label: "UNKNOWN", value: 5000 }, -]; - */ - const syslogCount = await LinuxLogModel.countDocuments({ logType: 'SYSLOG' }); const windowlogCount = await LinuxLogModel.countDocuments({ logType: 'WINDOWLOG' }); const authlogCount = await LinuxLogModel.countDocuments({ logType: 'AUTH' }); diff --git a/backend/src/routes/severityInfo.ts b/backend/src/routes/severityInfo.ts new file mode 100644 index 00000000..bd65113a --- /dev/null +++ b/backend/src/routes/severityInfo.ts @@ -0,0 +1,74 @@ +// total no of each severity "INFO" | "WARNING" | "ERROR" | "CRITICAL" and from last 7 months count for each severity in following format const [logData, setLogData] = React.useState({ +// info: [0, 0, 0, 0, 0, 0, 0], +// warning: [0, 0, 0, 0, 0, 0, 0], +// error: [0, 0, 0, 0, 0, 0, 0], +// critical: [0, 0, 0, 0, 0, 0, 0], +// }); + +import express from 'express'; +import { Request, Response } from 'express'; +import { LinuxLogModel } from '../models/LinuxLogModel'; + +const router = express.Router(); + +router.get('/severityInfo', async (req: Request, res: Response) => { + try { + + const info = [0, 0, 0, 0, 0, 0, 0]; + const warning = [0, 0, 0, 0, 0, 0, 0]; + const error = [0, 0, 0, 0, 0, 0, 0]; + const critical = [0, 0, 0, 0, 0, 0, 0]; + + // Get monthly data for the last 7 months + for (let i = 0; i < 7; i++) { + const monthStart = new Date(); + monthStart.setMonth(monthStart.getMonth() - i); + monthStart.setDate(1); + monthStart.setHours(0, 0, 0, 0); + + const monthEnd = new Date(monthStart); + monthEnd.setMonth(monthStart.getMonth() + 1); + monthEnd.setDate(0); + monthEnd.setHours(23, 59, 59, 999); + + info[6 - i] = await LinuxLogModel.countDocuments({ + severity: 'INFO', + timestamp: { $gte: monthStart, $lte: monthEnd } + }); + + warning[6 - i] = await LinuxLogModel.countDocuments({ + severity: 'WARNING', + timestamp: { $gte: monthStart, $lte: monthEnd } + }); + + error[6 - i] = await LinuxLogModel.countDocuments({ + severity: 'ERROR', + timestamp: { $gte: monthStart, $lte: monthEnd } + }); + + critical[6 - i] = await LinuxLogModel.countDocuments({ + severity: 'CRITICAL', + timestamp: { $gte: monthStart, $lte: monthEnd } + }); + } + + // Prepare response with total counts and monthly data + res.json({ + info, + warning, + error, + critical, + }); + + } catch (error) { + console.error(error); + res.status(500).json({ error: "Something went wrong." }); + } +}); + + + +export default router; + + + From 004686d0203c3b5500ca847542239576cd2e8453 Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Sat, 29 Mar 2025 01:08:42 +0530 Subject: [PATCH 10/11] feat: completes log severity status and fetch work on frontend --- .../src/components/LogAnalyzedBarGraph.jsx | 113 +++++++++++++++--- frontend/src/components/LogTypeStatus.jsx | 1 - frontend/src/utils/api/severityInfo.js | 14 +++ 3 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 frontend/src/utils/api/severityInfo.js diff --git a/frontend/src/components/LogAnalyzedBarGraph.jsx b/frontend/src/components/LogAnalyzedBarGraph.jsx index bec8cec3..03c81158 100644 --- a/frontend/src/components/LogAnalyzedBarGraph.jsx +++ b/frontend/src/components/LogAnalyzedBarGraph.jsx @@ -6,14 +6,85 @@ import Typography from "@mui/material/Typography"; import Stack from "@mui/material/Stack"; import { BarChart } from "@mui/x-charts/BarChart"; import { useTheme } from "@mui/material/styles"; +import severityInfo from "../utils/api/severityInfo"; export default function LogAnalyzedBarChart() { const theme = useTheme(); const colorPalette = [ - (theme.vars || theme).palette.primary.dark, - (theme.vars || theme).palette.primary.main, - (theme.vars || theme).palette.primary.light, + (theme.vars || theme).palette.info.main, // INFO + (theme.vars || theme).palette.warning.main, // WARNING + (theme.vars || theme).palette.error.main, // ERROR + (theme.vars || theme).palette.error.dark, // CRITICAL ]; + + const [logData, setLogData] = React.useState({ + info: [0, 0, 0, 0, 0, 0, 0], + warning: [0, 0, 0, 0, 0, 0, 0], + error: [0, 0, 0, 0, 0, 0, 0], + critical: [0, 0, 0, 0, 0, 0, 0], + }); + const [totalLogs, setTotalLogs] = React.useState(0); + const [percentageChange, setPercentageChange] = React.useState(0); + const [months, setMonths] = React.useState([]); + + React.useEffect(() => { + // Get last 7 months + const getLastSevenMonths = () => { + const monthNames = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ]; + const result = []; + const currentDate = new Date(); + const currentMonth = currentDate.getMonth(); + + for (let i = 6; i >= 0; i--) { + const monthIndex = (currentMonth - i + 12) % 12; + result.push(monthNames[monthIndex]); + } + + return result; + }; + + setMonths(getLastSevenMonths()); + + // Fetch log data from backend + const fetchLogData = async () => { + try { + const response = await severityInfo(); + setLogData(response); + + const total = Object.values(response) + .flat() + .reduce((sum, val) => sum + val, 0); + setTotalLogs(total); + + if (response.percentageChange !== undefined) { + setPercentageChange(response.percentageChange); + } + } catch (error) { + console.error("Error fetching log data:", error); + } + }; + + fetchLogData(); + }, []); + + // Format number with K suffix if >= 1000 + const formatNumber = (num) => { + return num >= 1000 ? `${(num / 1000).toFixed(1)}K` : num.toString(); + }; + return ( @@ -30,9 +101,13 @@ export default function LogAnalyzedBarChart() { }} > - 12K + {formatNumber(totalLogs)} - + Logs analyzed in the last 30 days @@ -45,26 +120,32 @@ export default function LogAnalyzedBarChart() { { scaleType: "band", categoryGapRatio: 0.5, - data: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"], + data: months, }, ]} series={[ { - id: "windows", - label: "Windows Log", - data: [3250, 4720, 2890, 3610, 5240, 4180, 3960], + id: "info", + label: "INFO", + data: logData.info, + stack: "A", + }, + { + id: "warning", + label: "WARNING", + data: logData.warning, stack: "A", }, { - id: "linux", - label: "Linux Log", - data: [2140, 3680, 4210, 3570, 2980, 4520, 3790], + id: "error", + label: "ERROR", + data: logData.error, stack: "A", }, { - id: "errors", - label: "Errors", - data: [780, 1240, 950, 1460, 1120, 860, 1320], + id: "critical", + label: "CRITICAL", + data: logData.critical, stack: "A", }, ]} @@ -73,7 +154,7 @@ export default function LogAnalyzedBarChart() { grid={{ horizontal: true }} slotProps={{ legend: { - hidden: true, + hidden: false, }, }} /> diff --git a/frontend/src/components/LogTypeStatus.jsx b/frontend/src/components/LogTypeStatus.jsx index 6496340d..4d049d2e 100644 --- a/frontend/src/components/LogTypeStatus.jsx +++ b/frontend/src/components/LogTypeStatus.jsx @@ -96,7 +96,6 @@ export default function LogTypeStatus() { const fetchData = async () => { try { const response = await logtypeStatus(); - console.log("LogTypeStatus response:", response); setData(response); //convert to string with the K notation diff --git a/frontend/src/utils/api/severityInfo.js b/frontend/src/utils/api/severityInfo.js new file mode 100644 index 00000000..6c7e8350 --- /dev/null +++ b/frontend/src/utils/api/severityInfo.js @@ -0,0 +1,14 @@ + +export default async function severityInfo() { + const data = await fetch(`${import.meta.env.VITE_BACKEND_URL}/api/severityInfo`) + + if(!data.ok) { + throw new Error("Network response was not ok" + data.statusText); + } + + const dataJson = await data.json(); + if (!dataJson) { + throw new Error("No data found"); + } + return dataJson; +} From c6afdf21a548c1a3931617609dde6307bf1e13da Mon Sep 17 00:00:00 2001 From: Dinesh Kumar Sutihar Date: Sat, 29 Mar 2025 01:10:49 +0530 Subject: [PATCH 11/11] wip: line graph to to show tend of logs over time --- frontend/src/components/MainGrid.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/MainGrid.jsx b/frontend/src/components/MainGrid.jsx index 1cb90bf9..bff1652b 100644 --- a/frontend/src/components/MainGrid.jsx +++ b/frontend/src/components/MainGrid.jsx @@ -55,13 +55,14 @@ export default function MainGrid() { - + {/* // TODO: add line Graph to show the trend of the logs over time */} + {/* - + */} ); }