Add Analytics Aggregator monitoring and status display
Integrates Analytics Aggregator status checks into the services overview, updating both backend route handling and frontend display components. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 7a657272-55ba-4a79-9a2e-f1ed9bc7a528 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 1211e51b-5231-4d36-9e68-107ca898152b Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/449cf7c4-c97a-45ae-8234-e5c5b8d6a84f/7a657272-55ba-4a79-9a2e-f1ed9bc7a528/0sf5i4S
This commit is contained in:
parent
edf7ef97f0
commit
402cbe1890
@ -27,6 +27,7 @@ interface ServicesStatusResponse {
|
||||
mlBackend: ServiceStatus;
|
||||
database: ServiceStatus;
|
||||
syslogParser: ServiceStatus;
|
||||
analyticsAggregator: ServiceStatus;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ interface ServicesStatusResponse {
|
||||
mlBackend: ServiceStatus;
|
||||
database: ServiceStatus;
|
||||
syslogParser: ServiceStatus;
|
||||
analyticsAggregator: ServiceStatus;
|
||||
};
|
||||
}
|
||||
|
||||
@ -321,6 +322,62 @@ export default function ServicesPage() {
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Analytics Aggregator Service */}
|
||||
<Card data-testid="card-analytics-aggregator-service">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-lg">
|
||||
<Activity className="h-5 w-5" />
|
||||
Analytics Aggregator
|
||||
{servicesStatus && getStatusIndicator(servicesStatus.services.analyticsAggregator)}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">Stato:</span>
|
||||
{servicesStatus && getStatusBadge(servicesStatus.services.analyticsAggregator)}
|
||||
</div>
|
||||
|
||||
{servicesStatus?.services.analyticsAggregator.details?.lastRun && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">Ultima Aggregazione:</span>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{new Date(servicesStatus.services.analyticsAggregator.details.lastRun).toLocaleString('it-IT')}
|
||||
</Badge>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{servicesStatus?.services.analyticsAggregator.details?.hoursSinceLastRun && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">Ore dall'ultimo run:</span>
|
||||
<Badge variant={parseFloat(servicesStatus.services.analyticsAggregator.details.hoursSinceLastRun) < 2 ? "default" : "secondary"}>
|
||||
{servicesStatus.services.analyticsAggregator.details.hoursSinceLastRun}h
|
||||
</Badge>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||
<p className="text-xs font-medium mb-2">Verifica timer:</p>
|
||||
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-status-aggregator">
|
||||
systemctl status ids-analytics-aggregator.timer
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||
<p className="text-xs font-medium mb-2">Avvia aggregazione manualmente:</p>
|
||||
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-run-aggregator">
|
||||
cd /opt/ids && ./deployment/run_analytics.sh
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||
<p className="text-xs font-medium mb-2">Log:</p>
|
||||
<code className="text-xs bg-background p-2 rounded block font-mono" data-testid="code-log-aggregator">
|
||||
journalctl -u ids-analytics-aggregator.timer -f
|
||||
</code>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Additional Commands */}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import type { Express } from "express";
|
||||
import { createServer, type Server } from "http";
|
||||
import { storage } from "./storage";
|
||||
import { insertRouterSchema, insertDetectionSchema, insertWhitelistSchema } from "@shared/schema";
|
||||
import { insertRouterSchema, insertDetectionSchema, insertWhitelistSchema, networkAnalytics } from "@shared/schema";
|
||||
import { db } from "./db";
|
||||
import { desc } from "drizzle-orm";
|
||||
|
||||
export async function registerRoutes(app: Express): Promise<Server> {
|
||||
// Routers
|
||||
@ -362,6 +364,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
mlBackend: { name: "ML Backend Python", status: "unknown", healthy: false, details: null as any },
|
||||
database: { name: "PostgreSQL Database", status: "unknown", healthy: false, details: null as any },
|
||||
syslogParser: { name: "Syslog Parser", status: "unknown", healthy: false, details: null as any },
|
||||
analyticsAggregator: { name: "Analytics Aggregator Timer", status: "unknown", healthy: false, details: null as any },
|
||||
};
|
||||
|
||||
// Check ML Backend Python
|
||||
@ -446,6 +449,45 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
};
|
||||
}
|
||||
|
||||
// Check Analytics Aggregator (via last record timestamp)
|
||||
try {
|
||||
const latestAnalytics = await db
|
||||
.select()
|
||||
.from(networkAnalytics)
|
||||
.orderBy(desc(networkAnalytics.date), desc(networkAnalytics.hour))
|
||||
.limit(1);
|
||||
|
||||
if (latestAnalytics.length > 0) {
|
||||
const lastRun = new Date(latestAnalytics[0].date);
|
||||
const hoursSinceLastRun = (Date.now() - lastRun.getTime()) / (1000 * 60 * 60);
|
||||
|
||||
if (hoursSinceLastRun < 2) {
|
||||
services.analyticsAggregator.status = "running";
|
||||
services.analyticsAggregator.healthy = true;
|
||||
services.analyticsAggregator.details = {
|
||||
lastRun: latestAnalytics[0].date,
|
||||
hoursSinceLastRun: hoursSinceLastRun.toFixed(1),
|
||||
};
|
||||
} else {
|
||||
services.analyticsAggregator.status = "idle";
|
||||
services.analyticsAggregator.healthy = false;
|
||||
services.analyticsAggregator.details = {
|
||||
lastRun: latestAnalytics[0].date,
|
||||
hoursSinceLastRun: hoursSinceLastRun.toFixed(1),
|
||||
warning: "No aggregation in last 2 hours",
|
||||
};
|
||||
}
|
||||
} else {
|
||||
services.analyticsAggregator.status = "idle";
|
||||
services.analyticsAggregator.healthy = false;
|
||||
services.analyticsAggregator.details = { error: "No analytics data found" };
|
||||
}
|
||||
} catch (error: any) {
|
||||
services.analyticsAggregator.status = "error";
|
||||
services.analyticsAggregator.healthy = false;
|
||||
services.analyticsAggregator.details = { error: error.message };
|
||||
}
|
||||
|
||||
res.json({ services });
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ error: "Failed to check services status" });
|
||||
|
||||
Loading…
Reference in New Issue
Block a user