mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-11 01:36:37 +08:00
Refactor dashboard overview: remove active alerts and lagging nodes from summary, update tests and components accordingly
- Removed active alerts and lagging nodes from DashboardSummary and related types. - Updated DashboardOverview component to reflect changes in data structure. - Adjusted tests to align with the new dashboard overview structure, ensuring no active alerts are displayed. - Simplified the dashboard metrics and risk signals, focusing on essential health and capacity metrics. - Enhanced the WorldStage component to present updated traffic and capacity information. - Removed unused alert-related functions and components to streamline the codebase.
This commit is contained in:
@@ -2,11 +2,8 @@ package service
|
||||
|
||||
import (
|
||||
"atsflare/model"
|
||||
"errors"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DashboardOverviewView struct {
|
||||
@@ -14,13 +11,9 @@ type DashboardOverviewView struct {
|
||||
Summary DashboardSummary `json:"summary"`
|
||||
Traffic DashboardTraffic `json:"traffic"`
|
||||
Capacity DashboardCapacity `json:"capacity"`
|
||||
Config DashboardConfig `json:"config"`
|
||||
Risk DashboardRiskSummary `json:"risk"`
|
||||
Peaks DashboardPeakSummary `json:"peaks"`
|
||||
Distributions TrafficDistributions `json:"distributions"`
|
||||
Trends DashboardTrends `json:"trends"`
|
||||
Nodes []DashboardNodeHealth `json:"nodes"`
|
||||
ActiveAlerts []DashboardAlert `json:"active_alerts"`
|
||||
}
|
||||
|
||||
type DashboardSummary struct {
|
||||
@@ -29,8 +22,6 @@ type DashboardSummary struct {
|
||||
OfflineNodes int `json:"offline_nodes"`
|
||||
PendingNodes int `json:"pending_nodes"`
|
||||
UnhealthyNodes int `json:"unhealthy_nodes"`
|
||||
ActiveAlerts int `json:"active_alerts"`
|
||||
LaggingNodes int `json:"lagging_nodes"`
|
||||
}
|
||||
|
||||
type DashboardTraffic struct {
|
||||
@@ -49,48 +40,6 @@ type DashboardCapacity struct {
|
||||
HighStorageNodes int `json:"high_storage_nodes"`
|
||||
}
|
||||
|
||||
type DashboardConfig struct {
|
||||
ActiveVersion string `json:"active_version"`
|
||||
LaggingNodes int `json:"lagging_nodes"`
|
||||
PendingNodes int `json:"pending_nodes"`
|
||||
}
|
||||
|
||||
type DashboardRiskSummary struct {
|
||||
CriticalAlerts int `json:"critical_alerts"`
|
||||
WarningAlerts int `json:"warning_alerts"`
|
||||
InfoAlerts int `json:"info_alerts"`
|
||||
OfflineNodes int `json:"offline_nodes"`
|
||||
UnhealthyNodes int `json:"unhealthy_nodes"`
|
||||
LaggingNodes int `json:"lagging_nodes"`
|
||||
HighCPUNodes int `json:"high_cpu_nodes"`
|
||||
HighMemoryNodes int `json:"high_memory_nodes"`
|
||||
HighStorageNodes int `json:"high_storage_nodes"`
|
||||
}
|
||||
|
||||
type DashboardPeakSummary struct {
|
||||
PeakRequestHour DashboardPeakHour `json:"peak_request_hour"`
|
||||
PeakErrorHour DashboardPeakHour `json:"peak_error_hour"`
|
||||
BusiestNode *DashboardPeakNode `json:"busiest_node"`
|
||||
RiskiestNode *DashboardPeakNode `json:"riskiest_node"`
|
||||
}
|
||||
|
||||
type DashboardPeakHour struct {
|
||||
BucketStartedAt time.Time `json:"bucket_started_at"`
|
||||
RequestCount int64 `json:"request_count"`
|
||||
ErrorCount int64 `json:"error_count"`
|
||||
}
|
||||
|
||||
type DashboardPeakNode struct {
|
||||
NodeID string `json:"node_id"`
|
||||
NodeName string `json:"node_name"`
|
||||
RequestCount int64 `json:"request_count"`
|
||||
ErrorCount int64 `json:"error_count"`
|
||||
CPUUsagePercent float64 `json:"cpu_usage_percent"`
|
||||
ActiveEventCount int `json:"active_event_count"`
|
||||
OpenrestyStatus string `json:"openresty_status"`
|
||||
StorageUsagePercent float64 `json:"storage_usage_percent"`
|
||||
}
|
||||
|
||||
type DashboardTrends struct {
|
||||
Traffic24h []TrafficTrendPoint `json:"traffic_24h"`
|
||||
Capacity24h []CapacityTrendPoint `json:"capacity_24h"`
|
||||
@@ -118,16 +67,6 @@ type DashboardNodeHealth struct {
|
||||
UniqueVisitorCount int64 `json:"unique_visitor_count"`
|
||||
}
|
||||
|
||||
type DashboardAlert struct {
|
||||
NodeID string `json:"node_id"`
|
||||
NodeName string `json:"node_name"`
|
||||
EventType string `json:"event_type"`
|
||||
Severity string `json:"severity"`
|
||||
Message string `json:"message"`
|
||||
LastTriggeredAt time.Time `json:"last_triggered_at"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func GetDashboardOverview() (*DashboardOverviewView, error) {
|
||||
now := time.Now()
|
||||
since := now.Add(-24 * time.Hour)
|
||||
@@ -137,13 +76,6 @@ func GetDashboardOverview() (*DashboardOverviewView, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
activeVersion := ""
|
||||
if version, versionErr := model.GetActiveConfigVersion(); versionErr == nil {
|
||||
activeVersion = version.Version
|
||||
} else if !errors.Is(versionErr, gorm.ErrRecordNotFound) {
|
||||
return nil, versionErr
|
||||
}
|
||||
|
||||
snapshots, err := model.ListMetricSnapshotsSince(since)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -160,7 +92,6 @@ func GetDashboardOverview() (*DashboardOverviewView, error) {
|
||||
view := &DashboardOverviewView{
|
||||
GeneratedAt: now,
|
||||
Nodes: make([]DashboardNodeHealth, 0, len(nodes)),
|
||||
ActiveAlerts: make([]DashboardAlert, 0),
|
||||
Distributions: buildTrafficDistributions(reports, 8),
|
||||
Trends: DashboardTrends{
|
||||
Traffic24h: buildTrafficTrendPoints(now, reports),
|
||||
@@ -183,21 +114,11 @@ func GetDashboardOverview() (*DashboardOverviewView, error) {
|
||||
view.Summary.OnlineNodes++
|
||||
case NodeStatusOffline:
|
||||
view.Summary.OfflineNodes++
|
||||
view.Risk.OfflineNodes++
|
||||
case NodeStatusPending:
|
||||
view.Summary.PendingNodes++
|
||||
}
|
||||
if node.OpenrestyStatus == OpenrestyStatusUnhealthy {
|
||||
view.Summary.UnhealthyNodes++
|
||||
view.Risk.UnhealthyNodes++
|
||||
}
|
||||
if activeVersion != "" && node.CurrentVersion != "" && node.CurrentVersion != activeVersion {
|
||||
view.Summary.LaggingNodes++
|
||||
view.Risk.LaggingNodes++
|
||||
}
|
||||
if activeVersion != "" && node.CurrentVersion == "" && computedStatus != NodeStatusPending {
|
||||
view.Summary.LaggingNodes++
|
||||
view.Risk.LaggingNodes++
|
||||
}
|
||||
|
||||
latestSnapshot := latestSnapshots[node.NodeID]
|
||||
@@ -218,26 +139,6 @@ func GetDashboardOverview() (*DashboardOverviewView, error) {
|
||||
ActiveEventCount: len(nodeActiveEvents),
|
||||
}
|
||||
|
||||
for _, event := range nodeActiveEvents {
|
||||
view.ActiveAlerts = append(view.ActiveAlerts, DashboardAlert{
|
||||
NodeID: node.NodeID,
|
||||
NodeName: node.Name,
|
||||
EventType: event.EventType,
|
||||
Severity: event.Severity,
|
||||
Message: event.Message,
|
||||
LastTriggeredAt: event.LastTriggeredAt,
|
||||
Status: event.Status,
|
||||
})
|
||||
switch event.Severity {
|
||||
case NodeHealthSeverityCritical:
|
||||
view.Risk.CriticalAlerts++
|
||||
case NodeHealthSeverityWarning:
|
||||
view.Risk.WarningAlerts++
|
||||
default:
|
||||
view.Risk.InfoAlerts++
|
||||
}
|
||||
}
|
||||
|
||||
if latestSnapshot != nil {
|
||||
nodeHealth.CPUUsagePercent = latestSnapshot.CPUUsagePercent
|
||||
nodeHealth.MemoryUsagePercent = percentage(latestSnapshot.MemoryUsedBytes, latestSnapshot.MemoryTotalBytes)
|
||||
@@ -252,15 +153,12 @@ func GetDashboardOverview() (*DashboardOverviewView, error) {
|
||||
}
|
||||
if latestSnapshot.CPUUsagePercent >= 80 {
|
||||
view.Capacity.HighCPUNodes++
|
||||
view.Risk.HighCPUNodes++
|
||||
}
|
||||
if nodeHealth.MemoryUsagePercent >= 85 {
|
||||
view.Capacity.HighMemoryNodes++
|
||||
view.Risk.HighMemoryNodes++
|
||||
}
|
||||
if nodeHealth.StorageUsagePercent >= 85 {
|
||||
view.Capacity.HighStorageNodes++
|
||||
view.Risk.HighStorageNodes++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,14 +175,10 @@ func GetDashboardOverview() (*DashboardOverviewView, error) {
|
||||
view.Traffic.ReportedNodes++
|
||||
}
|
||||
|
||||
view.Summary.ActiveAlerts += len(nodeActiveEvents)
|
||||
view.Nodes = append(view.Nodes, nodeHealth)
|
||||
}
|
||||
|
||||
view.Summary.TotalNodes = len(nodes)
|
||||
view.Config.ActiveVersion = activeVersion
|
||||
view.Config.LaggingNodes = view.Summary.LaggingNodes
|
||||
view.Config.PendingNodes = view.Summary.PendingNodes
|
||||
|
||||
if cpuNodeCount > 0 {
|
||||
view.Capacity.AverageCPUUsagePercent /= float64(cpuNodeCount)
|
||||
@@ -293,13 +187,6 @@ func GetDashboardOverview() (*DashboardOverviewView, error) {
|
||||
view.Capacity.AverageMemoryUsagePercent /= float64(memoryNodeCount)
|
||||
}
|
||||
|
||||
sort.Slice(view.ActiveAlerts, func(i int, j int) bool {
|
||||
if severityWeight(view.ActiveAlerts[i].Severity) == severityWeight(view.ActiveAlerts[j].Severity) {
|
||||
return view.ActiveAlerts[i].LastTriggeredAt.After(view.ActiveAlerts[j].LastTriggeredAt)
|
||||
}
|
||||
return severityWeight(view.ActiveAlerts[i].Severity) > severityWeight(view.ActiveAlerts[j].Severity)
|
||||
})
|
||||
|
||||
sort.Slice(view.Nodes, func(i int, j int) bool {
|
||||
if view.Nodes[i].ActiveEventCount == view.Nodes[j].ActiveEventCount {
|
||||
return view.Nodes[i].CPUUsagePercent > view.Nodes[j].CPUUsagePercent
|
||||
@@ -307,19 +194,6 @@ func GetDashboardOverview() (*DashboardOverviewView, error) {
|
||||
return view.Nodes[i].ActiveEventCount > view.Nodes[j].ActiveEventCount
|
||||
})
|
||||
|
||||
if len(view.ActiveAlerts) > 8 {
|
||||
view.ActiveAlerts = view.ActiveAlerts[:8]
|
||||
}
|
||||
|
||||
view.Peaks.PeakRequestHour = peakTrafficHour(view.Trends.Traffic24h, func(point TrafficTrendPoint) int64 {
|
||||
return point.RequestCount
|
||||
})
|
||||
view.Peaks.PeakErrorHour = peakTrafficHour(view.Trends.Traffic24h, func(point TrafficTrendPoint) int64 {
|
||||
return point.ErrorCount
|
||||
})
|
||||
view.Peaks.BusiestNode = busiestDashboardNode(view.Nodes)
|
||||
view.Peaks.RiskiestNode = riskiestDashboardNode(view.Nodes)
|
||||
|
||||
return view, nil
|
||||
}
|
||||
|
||||
@@ -368,69 +242,3 @@ func activeHealthEventsByNode(events []*model.NodeHealthEvent) map[string][]*mod
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func severityWeight(severity string) int {
|
||||
switch severity {
|
||||
case NodeHealthSeverityCritical:
|
||||
return 3
|
||||
case NodeHealthSeverityWarning:
|
||||
return 2
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
func peakTrafficHour(points []TrafficTrendPoint, selector func(point TrafficTrendPoint) int64) DashboardPeakHour {
|
||||
var result DashboardPeakHour
|
||||
var maxValue int64 = -1
|
||||
for _, point := range points {
|
||||
value := selector(point)
|
||||
if value <= maxValue {
|
||||
continue
|
||||
}
|
||||
maxValue = value
|
||||
result = DashboardPeakHour{
|
||||
BucketStartedAt: point.BucketStartedAt,
|
||||
RequestCount: point.RequestCount,
|
||||
ErrorCount: point.ErrorCount,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func busiestDashboardNode(nodes []DashboardNodeHealth) *DashboardPeakNode {
|
||||
var selected *DashboardPeakNode
|
||||
for _, node := range nodes {
|
||||
candidate := &DashboardPeakNode{
|
||||
NodeID: node.NodeID,
|
||||
NodeName: node.Name,
|
||||
RequestCount: node.RequestCount,
|
||||
ErrorCount: node.ErrorCount,
|
||||
CPUUsagePercent: node.CPUUsagePercent,
|
||||
ActiveEventCount: node.ActiveEventCount,
|
||||
OpenrestyStatus: node.OpenrestyStatus,
|
||||
StorageUsagePercent: node.StorageUsagePercent,
|
||||
}
|
||||
if selected == nil || candidate.RequestCount > selected.RequestCount || (candidate.RequestCount == selected.RequestCount && candidate.ErrorCount > selected.ErrorCount) {
|
||||
selected = candidate
|
||||
}
|
||||
}
|
||||
return selected
|
||||
}
|
||||
|
||||
func riskiestDashboardNode(nodes []DashboardNodeHealth) *DashboardPeakNode {
|
||||
if len(nodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
node := nodes[0]
|
||||
return &DashboardPeakNode{
|
||||
NodeID: node.NodeID,
|
||||
NodeName: node.Name,
|
||||
RequestCount: node.RequestCount,
|
||||
ErrorCount: node.ErrorCount,
|
||||
CPUUsagePercent: node.CPUUsagePercent,
|
||||
ActiveEventCount: node.ActiveEventCount,
|
||||
OpenrestyStatus: node.OpenrestyStatus,
|
||||
StorageUsagePercent: node.StorageUsagePercent,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1005,24 +1005,24 @@ func TestGetDashboardOverview(t *testing.T) {
|
||||
if view.Summary.TotalNodes != 2 || view.Summary.OnlineNodes != 2 {
|
||||
t.Fatalf("unexpected dashboard summary: %+v", view.Summary)
|
||||
}
|
||||
if view.Summary.UnhealthyNodes != 1 || view.Summary.ActiveAlerts != 1 {
|
||||
t.Fatalf("unexpected unhealthy/alert summary: %+v", view.Summary)
|
||||
if view.Summary.UnhealthyNodes != 1 {
|
||||
t.Fatalf("unexpected unhealthy summary: %+v", view.Summary)
|
||||
}
|
||||
if view.Traffic.RequestCount != 900 || view.Traffic.ErrorCount != 36 {
|
||||
t.Fatalf("unexpected dashboard traffic: %+v", view.Traffic)
|
||||
}
|
||||
if view.Config.ActiveVersion != "20260314-001" || view.Config.LaggingNodes != 1 {
|
||||
t.Fatalf("unexpected dashboard config summary: %+v", view.Config)
|
||||
if view.Capacity.HighCPUNodes != 1 || view.Capacity.HighMemoryNodes != 1 {
|
||||
t.Fatalf("unexpected dashboard capacity summary: %+v", view.Capacity)
|
||||
}
|
||||
if view.Risk.CriticalAlerts != 1 || view.Risk.HighCPUNodes != 1 || view.Risk.HighMemoryNodes != 1 {
|
||||
t.Fatalf("unexpected dashboard risk summary: %+v", view.Risk)
|
||||
}
|
||||
if len(view.Nodes) != 2 || len(view.ActiveAlerts) != 1 {
|
||||
t.Fatalf("unexpected dashboard nodes/alerts: %+v %+v", view.Nodes, view.ActiveAlerts)
|
||||
if len(view.Nodes) != 2 {
|
||||
t.Fatalf("unexpected dashboard nodes: %+v", view.Nodes)
|
||||
}
|
||||
if view.Nodes[0].GeoName == "" && view.Nodes[1].GeoName == "" {
|
||||
t.Fatalf("expected dashboard nodes to expose geo metadata: %+v", view.Nodes)
|
||||
}
|
||||
if view.Nodes[0].ActiveEventCount != 1 {
|
||||
t.Fatalf("expected dashboard nodes to preserve active event counts: %+v", view.Nodes)
|
||||
}
|
||||
if len(view.Trends.Traffic24h) != 24 || len(view.Trends.Capacity24h) != 24 || len(view.Trends.Network24h) != 24 || len(view.Trends.DiskIO24h) != 24 {
|
||||
t.Fatalf("expected 24-point dashboard trends, got %+v", view.Trends)
|
||||
}
|
||||
@@ -1044,25 +1044,19 @@ func TestGetDashboardOverview(t *testing.T) {
|
||||
if len(view.Distributions.TopDomains) == 0 || view.Distributions.TopDomains[0].Key != "app.example.com" {
|
||||
t.Fatalf("unexpected dashboard domain distributions: %+v", view.Distributions.TopDomains)
|
||||
}
|
||||
if view.Peaks.BusiestNode == nil || view.Peaks.BusiestNode.NodeID != "node-dashboard-a" {
|
||||
t.Fatalf("unexpected busiest node: %+v", view.Peaks.BusiestNode)
|
||||
}
|
||||
if view.Peaks.RiskiestNode == nil || view.Peaks.RiskiestNode.NodeID != "node-dashboard-b" {
|
||||
t.Fatalf("unexpected riskiest node: %+v", view.Peaks.RiskiestNode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDashboardOverviewReturnsEmptyAlertSlice(t *testing.T) {
|
||||
func TestGetDashboardOverviewReturnsEmptyNodeSlice(t *testing.T) {
|
||||
setupServiceTestDB(t)
|
||||
|
||||
view, err := GetDashboardOverview()
|
||||
if err != nil {
|
||||
t.Fatalf("GetDashboardOverview failed: %v", err)
|
||||
}
|
||||
if view.ActiveAlerts == nil {
|
||||
t.Fatalf("expected active alerts to be an empty slice, got nil")
|
||||
if view.Nodes == nil {
|
||||
t.Fatalf("expected nodes to be an empty slice, got nil")
|
||||
}
|
||||
if len(view.ActiveAlerts) != 0 {
|
||||
t.Fatalf("expected empty active alerts, got %+v", view.ActiveAlerts)
|
||||
if len(view.Nodes) != 0 {
|
||||
t.Fatalf("expected empty nodes, got %+v", view.Nodes)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user