fix: 修复 Agent 状态与监控大屏
This commit is contained in:
1 parent
83662487cb
commit
e557782176
9 files changed
+155
-591
No files matched your search
+38
-29
@@ -61,29 +61,30 @@ func (h *AgentHandler) ReceiveReport(c *gin.Context) {
|
||||
|
||||
// 存储到数据库
|
||||
report := model.AgentReport{
|
||||
Hostname: req.Hostname,
|
||||
CPUUsage: req.CPU.UsagePercent,
|
||||
CPUIOwait: req.CPU.IOWait,
|
||||
CPUCores: req.CPU.CoreCount,
|
||||
Load1: req.CPU.Load1,
|
||||
Load5: req.CPU.Load5,
|
||||
Load15: req.CPU.Load15,
|
||||
MemTotal: req.Memory.TotalGB,
|
||||
MemUsed: req.Memory.UsedGB,
|
||||
MemUsage: req.Memory.UsagePercent,
|
||||
Hostname: req.Hostname,
|
||||
IP: strings.TrimSpace(req.IP), // 使用 Agent 自报 IP,避免反向代理地址误关联。 // Logan.Li
|
||||
CPUUsage: req.CPU.UsagePercent,
|
||||
CPUIOwait: req.CPU.IOWait,
|
||||
CPUCores: req.CPU.CoreCount,
|
||||
Load1: req.CPU.Load1,
|
||||
Load5: req.CPU.Load5,
|
||||
Load15: req.CPU.Load15,
|
||||
MemTotal: req.Memory.TotalGB,
|
||||
MemUsed: req.Memory.UsedGB,
|
||||
MemUsage: req.Memory.UsagePercent,
|
||||
MemAvailable: req.Memory.AvailableGB,
|
||||
MemSwapUsed: req.Memory.SwapUsedGB,
|
||||
DiskInfo: string(diskJSON),
|
||||
PortInfo: string(portJSON),
|
||||
NetInfo: string(netJSON),
|
||||
DiskIOInfo: string(dioJSON),
|
||||
DiskInfo: string(diskJSON),
|
||||
PortInfo: string(portJSON),
|
||||
NetInfo: string(netJSON),
|
||||
DiskIOInfo: string(dioJSON),
|
||||
// v2.0 新增
|
||||
SwapInfo: string(swapJSON),
|
||||
ProcessTopInfo: string(processTopJSON),
|
||||
FDInfo: string(fdJSON),
|
||||
CSInfo: string(csJSON),
|
||||
HeartbeatInfo: string(heartbeatJSON),
|
||||
ReportTime: reportTime,
|
||||
ReportTime: reportTime,
|
||||
}
|
||||
|
||||
if err := h.db.Create(&report).Error; err != nil {
|
||||
@@ -99,9 +100,9 @@ func (h *AgentHandler) ReceiveReport(c *gin.Context) {
|
||||
for _, d := range req.Disks {
|
||||
totalDiskGB += d.TotalGB
|
||||
}
|
||||
memGB := math.Ceil(req.Memory.TotalGB) // 31.34 → 32, 62.79 → 63(物理内存向上取整)
|
||||
memMB := int64(memGB * 1024) // GB → MB
|
||||
diskGB := int64(totalDiskGB + 0.5) // 39.99 → 40
|
||||
memGB := math.Ceil(req.Memory.TotalGB) // 31.34 → 32, 62.79 → 63(物理内存向上取整)
|
||||
memMB := int64(memGB * 1024) // GB → MB
|
||||
diskGB := int64(totalDiskGB + 0.5) // 39.99 → 40
|
||||
|
||||
clientIP := c.ClientIP()
|
||||
|
||||
@@ -277,7 +278,7 @@ func (h *AgentHandler) writeHotMetric(c *gin.Context, key string, value float64,
|
||||
func (h *AgentHandler) GetLatestReports(c *gin.Context) {
|
||||
var results []model.AgentLatestResponse
|
||||
threeMinAgo := time.Now().Add(-3 * time.Minute)
|
||||
// 以 servers 表为主,LEFT JOIN 最近 3 分钟内的 Agent 上报
|
||||
// 以 servers 表为主,按资产名或 Agent 自报 IP 关联最近 3 分钟内的上报。 // Logan.Li
|
||||
// 未装 Agent 的主机也会显示(agent_status='not_installed'),打破"不显示→无法安装"的循环
|
||||
h.db.Raw(`
|
||||
SELECT
|
||||
@@ -302,7 +303,8 @@ func (h *AgentHandler) GetLatestReports(c *gin.Context) {
|
||||
a.report_time,
|
||||
COALESCE(s.agent_version, '') as agent_version,
|
||||
CASE
|
||||
WHEN a.hostname IS NOT NULL THEN COALESCE(s.agent_status, 'online')
|
||||
WHEN a.id IS NOT NULL THEN 'online'
|
||||
WHEN COALESCE(s.agent_version, '') <> '' OR COALESCE(s.agent_status, '') = 'online' THEN 'offline'
|
||||
ELSE 'not_installed'
|
||||
END as agent_status,
|
||||
COALESCE(s.os, '') as os,
|
||||
@@ -312,14 +314,13 @@ func (h *AgentHandler) GetLatestReports(c *gin.Context) {
|
||||
COALESCE(r.name, '') as region,
|
||||
CASE WHEN s.password != '' OR s.ssh_key != '' THEN true ELSE false END as has_auth
|
||||
FROM asset_servers s
|
||||
LEFT JOIN (
|
||||
SELECT * FROM monitor_agent_reports
|
||||
WHERE id IN (
|
||||
SELECT MAX(id) FROM monitor_agent_reports
|
||||
WHERE report_time >= ?
|
||||
GROUP BY hostname
|
||||
)
|
||||
) a ON a.hostname = s.hostname
|
||||
LEFT JOIN monitor_agent_reports a ON a.id = (
|
||||
SELECT ar.id FROM monitor_agent_reports ar
|
||||
WHERE ar.report_time >= ?
|
||||
AND (ar.hostname = s.hostname OR (ar.ip <> '' AND ar.ip = s.ip))
|
||||
ORDER BY ar.report_time DESC, ar.id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
LEFT JOIN asset_regions r ON r.id = s.region_id
|
||||
ORDER BY a.report_time DESC, s.id ASC
|
||||
`, threeMinAgo).Scan(&results)
|
||||
@@ -409,8 +410,16 @@ func (h *AgentHandler) GetHostHistory(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var server model.Server
|
||||
serverIP := ""
|
||||
if h.db.Where("hostname = ?", hostname).Take(&server).Error == nil {
|
||||
serverIP = strings.TrimSpace(server.IP)
|
||||
}
|
||||
|
||||
var reports []model.AgentReport
|
||||
h.db.Where("hostname = ? AND report_time >= ? AND report_time <= ?", hostname, since, until).
|
||||
// 资产名可能与操作系统主机名不同,优先兼容 Agent 自报 IP。 // Logan.Li
|
||||
h.db.Where("hostname = ? OR (ip <> '' AND ip = ?)", hostname, serverIP).
|
||||
Where("report_time >= ? AND report_time <= ?", since, until).
|
||||
Order("report_time ASC").
|
||||
Find(&reports)
|
||||
|
||||
|
||||
+60
-60
@@ -6,33 +6,34 @@ import (
|
||||
|
||||
// AgentReport Agent 上报的原始指标数据 // Logan.Li
|
||||
type AgentReport struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
Hostname string `gorm:"size:255;index;not null" json:"hostname"`
|
||||
CPUUsage float64 `gorm:"type:decimal(6,2)" json:"cpu_usage"`
|
||||
CPUIOwait float64 `gorm:"type:decimal(6,2)" json:"cpu_iowait"`
|
||||
CPUCores int `json:"cpu_cores"`
|
||||
Load1 float64 `gorm:"type:decimal(8,2)" json:"load1"`
|
||||
Load5 float64 `gorm:"type:decimal(8,2)" json:"load5"`
|
||||
Load15 float64 `gorm:"type:decimal(8,2)" json:"load15"`
|
||||
MemTotal float64 `gorm:"type:decimal(10,2)" json:"mem_total"`
|
||||
MemUsed float64 `gorm:"type:decimal(10,2)" json:"mem_used"`
|
||||
MemUsage float64 `gorm:"type:decimal(6,2)" json:"mem_usage"`
|
||||
MemAvailable float64 `gorm:"type:decimal(10,2)" json:"mem_available"`
|
||||
MemSwapUsed float64 `gorm:"type:decimal(10,2)" json:"mem_swap_used"`
|
||||
DiskInfo string `gorm:"type:text" json:"disk_info"`
|
||||
PortInfo string `gorm:"type:text" json:"port_info"`
|
||||
NetInfo string `gorm:"type:text" json:"net_info"`
|
||||
DiskIOInfo string `gorm:"type:text" json:"disk_io_info"`
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
Hostname string `gorm:"size:255;index;not null" json:"hostname"`
|
||||
IP string `gorm:"size:64;index" json:"ip"` // Agent 上报的本机 IP,用于资产别名关联。 // Logan.Li
|
||||
CPUUsage float64 `gorm:"type:decimal(6,2)" json:"cpu_usage"`
|
||||
CPUIOwait float64 `gorm:"type:decimal(6,2)" json:"cpu_iowait"`
|
||||
CPUCores int `json:"cpu_cores"`
|
||||
Load1 float64 `gorm:"type:decimal(8,2)" json:"load1"`
|
||||
Load5 float64 `gorm:"type:decimal(8,2)" json:"load5"`
|
||||
Load15 float64 `gorm:"type:decimal(8,2)" json:"load15"`
|
||||
MemTotal float64 `gorm:"type:decimal(10,2)" json:"mem_total"`
|
||||
MemUsed float64 `gorm:"type:decimal(10,2)" json:"mem_used"`
|
||||
MemUsage float64 `gorm:"type:decimal(6,2)" json:"mem_usage"`
|
||||
MemAvailable float64 `gorm:"type:decimal(10,2)" json:"mem_available"`
|
||||
MemSwapUsed float64 `gorm:"type:decimal(10,2)" json:"mem_swap_used"`
|
||||
DiskInfo string `gorm:"type:text" json:"disk_info"`
|
||||
PortInfo string `gorm:"type:text" json:"port_info"`
|
||||
NetInfo string `gorm:"type:text" json:"net_info"`
|
||||
DiskIOInfo string `gorm:"type:text" json:"disk_io_info"`
|
||||
// ──── v2.0 新增字段 ────
|
||||
SwapInfo string `gorm:"type:text" json:"swap_info"` // Swap JSON
|
||||
ProcessTopInfo string `gorm:"type:text" json:"process_top_info"` // 进程 TOP JSON
|
||||
FDInfo string `gorm:"type:text" json:"fd_info"` // FD 句柄 JSON
|
||||
CSInfo string `gorm:"type:text" json:"cs_info"` // 上下文切换 JSON
|
||||
HeartbeatInfo string `gorm:"type:text" json:"heartbeat_info"` // Agent 心跳 JSON
|
||||
SwapInfo string `gorm:"type:text" json:"swap_info"` // Swap JSON
|
||||
ProcessTopInfo string `gorm:"type:text" json:"process_top_info"` // 进程 TOP JSON
|
||||
FDInfo string `gorm:"type:text" json:"fd_info"` // FD 句柄 JSON
|
||||
CSInfo string `gorm:"type:text" json:"cs_info"` // 上下文切换 JSON
|
||||
HeartbeatInfo string `gorm:"type:text" json:"heartbeat_info"` // Agent 心跳 JSON
|
||||
// ──────────────────────────
|
||||
ReportTime time.Time `json:"report_time"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
ReportTime time.Time `json:"report_time"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (AgentReport) TableName() string {
|
||||
@@ -41,20 +42,20 @@ func (AgentReport) TableName() string {
|
||||
|
||||
// AgentLatestResponse Agent 最新状态(含服务器元信息)
|
||||
type AgentLatestResponse struct {
|
||||
ServerID uint `json:"server_id"`
|
||||
Hostname string `json:"hostname"`
|
||||
IP string `json:"ip"`
|
||||
CPUUsage float64 `json:"cpu_usage"`
|
||||
CPUCores int `json:"cpu_cores"`
|
||||
MemUsage float64 `json:"mem_usage"`
|
||||
MemTotal float64 `json:"mem_total"`
|
||||
MemUsed float64 `json:"mem_used"`
|
||||
DiskUsage float64 `json:"disk_usage"`
|
||||
DiskTotal int64 `json:"disk_total"`
|
||||
DiskInfo string `json:"disk_info"`
|
||||
PortInfo string `json:"port_info"`
|
||||
NetInfo string `json:"net_info"`
|
||||
DiskIOInfo string `json:"disk_io_info"`
|
||||
ServerID uint `json:"server_id"`
|
||||
Hostname string `json:"hostname"`
|
||||
IP string `json:"ip"`
|
||||
CPUUsage float64 `json:"cpu_usage"`
|
||||
CPUCores int `json:"cpu_cores"`
|
||||
MemUsage float64 `json:"mem_usage"`
|
||||
MemTotal float64 `json:"mem_total"`
|
||||
MemUsed float64 `json:"mem_used"`
|
||||
DiskUsage float64 `json:"disk_usage"`
|
||||
DiskTotal int64 `json:"disk_total"`
|
||||
DiskInfo string `json:"disk_info"`
|
||||
PortInfo string `json:"port_info"`
|
||||
NetInfo string `json:"net_info"`
|
||||
DiskIOInfo string `json:"disk_io_info"`
|
||||
// ──── v2.0 新增 ────
|
||||
SwapInfo string `json:"swap_info"`
|
||||
ProcessTopInfo string `json:"process_top_info"`
|
||||
@@ -74,23 +75,23 @@ type AgentLatestResponse struct {
|
||||
|
||||
// AgentReportRequest Agent 上报请求体
|
||||
type AgentReportRequest struct {
|
||||
Hostname string `json:"hostname" binding:"required"`
|
||||
IP string `json:"ip"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
AgentVersion string `json:"agent_version"`
|
||||
CPU CPUMetric `json:"cpu"`
|
||||
Memory MemMetric `json:"memory"`
|
||||
Swap *SwapMetric `json:"swap,omitempty"`
|
||||
Disks []DiskMetric `json:"disks"`
|
||||
Ports []PortMetric `json:"ports"`
|
||||
Network NetworkStatModel `json:"network"`
|
||||
DiskIO DiskIOStatModel `json:"disk_io"`
|
||||
System *SystemStatModel `json:"system,omitempty"`
|
||||
Hostname string `json:"hostname" binding:"required"`
|
||||
IP string `json:"ip"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
AgentVersion string `json:"agent_version"`
|
||||
CPU CPUMetric `json:"cpu"`
|
||||
Memory MemMetric `json:"memory"`
|
||||
Swap *SwapMetric `json:"swap,omitempty"`
|
||||
Disks []DiskMetric `json:"disks"`
|
||||
Ports []PortMetric `json:"ports"`
|
||||
Network NetworkStatModel `json:"network"`
|
||||
DiskIO DiskIOStatModel `json:"disk_io"`
|
||||
System *SystemStatModel `json:"system,omitempty"`
|
||||
// ──── v2.0 新增 ────
|
||||
ProcessTop []ProcessMetric `json:"process_top,omitempty"`
|
||||
FD *FDMetric `json:"fd,omitempty"`
|
||||
ContextSwitches *CSMetric `json:"context_switches,omitempty"`
|
||||
Heartbeat HeartbeatMetric `json:"heartbeat"`
|
||||
ProcessTop []ProcessMetric `json:"process_top,omitempty"`
|
||||
FD *FDMetric `json:"fd,omitempty"`
|
||||
ContextSwitches *CSMetric `json:"context_switches,omitempty"`
|
||||
Heartbeat HeartbeatMetric `json:"heartbeat"`
|
||||
ProbeResults []HealthProbeResult `json:"probe_results,omitempty"` // v2.1 健康探针结果
|
||||
}
|
||||
|
||||
@@ -198,10 +199,10 @@ type DiskIOStatModel struct {
|
||||
|
||||
// AgentPortPolicy 主机端口监控策略 // Logan.Li
|
||||
type AgentPortPolicy struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
Hostname string `gorm:"size:255;uniqueIndex;not null" json:"hostname"`
|
||||
PortFilterMode string `gorm:"size:20;default:whitelist;not null" json:"port_filter_mode"` // whitelist / blacklist
|
||||
PortWhitelist string `gorm:"type:text" json:"port_whitelist"` // JSON 数组,如 [80,443,3306,6379]
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
Hostname string `gorm:"size:255;uniqueIndex;not null" json:"hostname"`
|
||||
PortFilterMode string `gorm:"size:20;default:whitelist;not null" json:"port_filter_mode"` // whitelist / blacklist
|
||||
PortWhitelist string `gorm:"type:text" json:"port_whitelist"` // JSON 数组,如 [80,443,3306,6379]
|
||||
}
|
||||
|
||||
func (AgentPortPolicy) TableName() string {
|
||||
@@ -214,4 +215,3 @@ type AgentPortPolicyDTO struct {
|
||||
PortFilterMode string `json:"port_filter_mode"`
|
||||
PortWhitelist []int `json:"port_whitelist"`
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user