diff --git a/agent/agent b/agent/agent index 30e71ae..ad97256 100755 Binary files a/agent/agent and b/agent/agent differ diff --git a/agent/main.go b/agent/main.go index d9771ac..775dcc8 100644 --- a/agent/main.go +++ b/agent/main.go @@ -29,15 +29,18 @@ type Config struct { APIPort int `json:"api_port"` // API端口 } +// NetworkInterfaceMetrics 网卡监控指标 +type NetworkInterfaceMetrics struct { + BytesSent uint64 `json:"bytes_sent"` + BytesReceived uint64 `json:"bytes_received"` +} + // Metrics 监控指标 type Metrics struct { - CPU float64 `json:"cpu"` - Memory float64 `json:"memory"` - Disk map[string]float64 `json:"disk"` - Network struct { - BytesSent uint64 `json:"bytes_sent"` - BytesReceived uint64 `json:"bytes_received"` - } `json:"network"` + CPU float64 `json:"cpu"` + Memory float64 `json:"memory"` + Disk map[string]float64 `json:"disk"` + Network map[string]NetworkInterfaceMetrics `json:"network"` } // 全局配置 @@ -47,10 +50,14 @@ var config Config var parsedInterval time.Duration // 保存上一次网络流量采集的数据 +type NetworkStats struct { + BytesSent uint64 + BytesReceived uint64 +} + var ( - lastBytesSent uint64 - lastBytesReceived uint64 - lastCollectTime time.Time + lastNetworkStats = make(map[string]NetworkStats) + lastCollectTime time.Time ) // 保存采集到的数据点 @@ -316,44 +323,67 @@ func collectDisk() (map[string]float64, error) { } // 采集网络流量 -func collectNetwork() (uint64, uint64, error) { - ioCounters, err := net.IOCounters(false) +func collectNetwork() (map[string]NetworkInterfaceMetrics, error) { + // 获取所有网卡的统计数据 + ioCounters, err := net.IOCounters(true) if err != nil { - return 0, 0, err + return nil, err } if len(ioCounters) == 0 { - return 0, 0, nil + return make(map[string]NetworkInterfaceMetrics), nil } - // 获取当前时间和流量 + // 获取当前时间 currentTime := time.Now() - currentBytesSent := ioCounters[0].BytesSent - currentBytesReceived := ioCounters[0].BytesRecv - // 计算速率 - var bytesSentRate, bytesReceivedRate uint64 - if !lastCollectTime.IsZero() { - // 计算时间差(秒) - timeDiff := currentTime.Sub(lastCollectTime).Seconds() - if timeDiff > 0 { - // 计算流量差 - sentDiff := currentBytesSent - lastBytesSent - receivedDiff := currentBytesReceived - lastBytesReceived + // 初始化返回值 + networkMetrics := make(map[string]NetworkInterfaceMetrics) - // 计算速率(bytes/s) - bytesSentRate = uint64(float64(sentDiff) / timeDiff) - bytesReceivedRate = uint64(float64(receivedDiff) / timeDiff) + // 遍历所有网卡 + for _, counter := range ioCounters { + // 获取当前网卡的流量 + currentBytesSent := counter.BytesSent + currentBytesReceived := counter.BytesRecv + + // 计算速率 + var bytesSentRate, bytesReceivedRate uint64 + if !lastCollectTime.IsZero() { + // 计算时间差(秒) + timeDiff := currentTime.Sub(lastCollectTime).Seconds() + if timeDiff > 0 { + // 获取上一次该网卡的流量 + lastStats, exists := lastNetworkStats[counter.Name] + if exists { + // 计算流量差 + sentDiff := currentBytesSent - lastStats.BytesSent + receivedDiff := currentBytesReceived - lastStats.BytesReceived + + // 计算速率(bytes/s) + bytesSentRate = uint64(float64(sentDiff) / timeDiff) + bytesReceivedRate = uint64(float64(receivedDiff) / timeDiff) + } + } + } + + // 更新上一次采集的值 + lastNetworkStats[counter.Name] = NetworkStats{ + BytesSent: currentBytesSent, + BytesReceived: currentBytesReceived, + } + + // 保存当前网卡的速率 + networkMetrics[counter.Name] = NetworkInterfaceMetrics{ + BytesSent: bytesSentRate, + BytesReceived: bytesReceivedRate, } } - // 更新上一次采集的值 - lastBytesSent = currentBytesSent - lastBytesReceived = currentBytesReceived + // 更新上一次采集时间 lastCollectTime = currentTime - // 返回速率而不是累计流量 - return bytesSentRate, bytesReceivedRate, nil + // 返回所有网卡的速率 + return networkMetrics, nil } // 采集所有监控指标 @@ -382,13 +412,12 @@ func collectMetrics() (*Metrics, error) { metrics.Disk = diskUsageMap // 采集网络流量 - bytesSent, bytesReceived, err := collectNetwork() + networkMetrics, err := collectNetwork() if err != nil { return nil, fmt.Errorf("failed to collect network metrics: %w", err) } - // 直接使用采集到的累计流量 - metrics.Network.BytesSent = bytesSent - metrics.Network.BytesReceived = bytesReceived + // 直接使用采集到的网卡流量 + metrics.Network = networkMetrics return metrics, nil } @@ -407,7 +436,7 @@ func sendMetrics(metricsList []*Metrics) error { } // 创建请求 - req, err := http.NewRequest("POST", fmt.Sprintf("%s/metrics", config.ServerURL), bytes.NewBuffer(jsonData)) + req, err := http.NewRequest("POST", fmt.Sprintf("%s/metrics/", config.ServerURL), bytes.NewBuffer(jsonData)) if err != nil { return err } diff --git a/agent/test_agent.json b/agent/test_agent.json new file mode 100644 index 0000000..fe4a7e6 --- /dev/null +++ b/agent/test_agent.json @@ -0,0 +1,10 @@ +{ + "server_url": "http://localhost:8080/api", + "id": "test-agent", + "name": "Test Agent", + "device_id": "test-device", + "token": "bb30bfaee01bf7b541bbefe422f72645", + "interval": "5s", + "debug": true, + "api_port": 8081 +} \ No newline at end of file diff --git a/agent/test_metrics.sh b/agent/test_metrics.sh new file mode 100755 index 0000000..9bec916 --- /dev/null +++ b/agent/test_metrics.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# 测试发送单个指标对象 +echo "测试发送单个指标对象:" +curl -v -X POST -H "Content-Type: application/json" -H "X-Device-ID: test-device" -H "X-Agent-Name: test-agent" -H "X-Device-Token: test-token" -d '{"cpu": 50.5, "memory": 30.2, "disk": {":/": 45.6}, "network": {"eth0": {"bytes_sent": 1000, "bytes_received": 2000}}}' http://localhost:8080/api/metrics/ + +echo "\n---\n" + +# 测试发送指标数组 +echo "测试发送指标数组:" +curl -v -X POST -H "Content-Type: application/json" -H "X-Device-ID: test-device" -H "X-Agent-Name: test-agent" -H "X-Device-Token: test-token" -d '[{"cpu": 50.5, "memory": 30.2, "disk": {":/": 45.6}, "network": {"eth0": {"bytes_sent": 1000, "bytes_received": 2000}}}, {"cpu": 60.5, "memory": 40.2, "disk": {":/": 55.6}, "network": {"eth0": {"bytes_sent": 2000, "bytes_received": 3000}}}]' http://localhost:8080/api/metrics/ diff --git a/backend/internal/handler/handler.go b/backend/internal/handler/handler.go index 0dc13ff..9962ba1 100644 --- a/backend/internal/handler/handler.go +++ b/backend/internal/handler/handler.go @@ -67,15 +67,18 @@ func RegisterRoutes(r *gin.Engine) { } } +// NetworkInterfaceMetrics 网卡监控指标 +type NetworkInterfaceMetrics struct { + BytesSent uint64 `json:"bytes_sent"` + BytesReceived uint64 `json:"bytes_received"` +} + // MetricsRequest 指标请求结构 type MetricsRequest struct { - CPU float64 `json:"cpu"` - Memory float64 `json:"memory"` - Disk map[string]float64 `json:"disk"` - Network struct { - BytesSent uint64 `json:"bytes_sent"` - BytesReceived uint64 `json:"bytes_received"` - } `json:"network"` + CPU float64 `json:"cpu"` + Memory float64 `json:"memory"` + Disk map[string]float64 `json:"disk"` + Network map[string]NetworkInterfaceMetrics `json:"network"` } // HandleMetricsPost 处理Agent发送的指标数据 @@ -127,11 +130,20 @@ func HandleMetricsPost(c *gin.Context) { // 处理请求体,支持单指标对象和指标数组 var metricsList []MetricsRequest + // 读取请求体到缓冲区,以便多次解析 + body, err := c.GetRawData() + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "error": "Failed to read request body", + }) + return + } + // 首先尝试解析为数组 - if err := c.ShouldBindJSON(&metricsList); err != nil { + if err := json.Unmarshal(body, &metricsList); err != nil { // 如果解析数组失败,尝试解析为单个对象 var singleMetric MetricsRequest - if err := c.ShouldBindJSON(&singleMetric); err != nil { + if err := json.Unmarshal(body, &singleMetric); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": "Invalid request body", }) @@ -173,16 +185,33 @@ func HandleMetricsPost(c *gin.Context) { } } - // 写入网络发送指标 - if err := globalStorage.WriteMetric(c.Request.Context(), deviceID, "network_sent", float64(req.Network.BytesSent), baseTags); err != nil { - // 只记录警告,不影响后续指标处理 - log.Printf("Warning: Failed to write network sent metrics: %v", err) - } + // 写入网络指标,支持多个网卡 + var totalBytesSent, totalBytesReceived uint64 + for interfaceName, networkMetrics := range req.Network { + // 为每个网卡创建标签,包含基础标签和网卡名称 + interfaceTags := make(map[string]string) + // 复制基础标签 + for k, v := range baseTags { + interfaceTags[k] = v + } + // 添加网卡标签 + interfaceTags["interface"] = interfaceName - // 写入网络接收指标 - if err := globalStorage.WriteMetric(c.Request.Context(), deviceID, "network_received", float64(req.Network.BytesReceived), baseTags); err != nil { - // 只记录警告,不影响后续指标处理 - log.Printf("Warning: Failed to write network received metrics: %v", err) + // 写入网络发送指标 + if err := globalStorage.WriteMetric(c.Request.Context(), deviceID, "network_sent", float64(networkMetrics.BytesSent), interfaceTags); err != nil { + // 只记录警告,不影响后续指标处理 + log.Printf("Warning: Failed to write network sent metrics for interface %s: %v", interfaceName, err) + } + + // 写入网络接收指标 + if err := globalStorage.WriteMetric(c.Request.Context(), deviceID, "network_received", float64(networkMetrics.BytesReceived), interfaceTags); err != nil { + // 只记录警告,不影响后续指标处理 + log.Printf("Warning: Failed to write network received metrics for interface %s: %v", interfaceName, err) + } + + // 累加总流量 + totalBytesSent += networkMetrics.BytesSent + totalBytesReceived += networkMetrics.BytesReceived } // 广播指标更新消息,只广播最后一个指标 @@ -192,9 +221,10 @@ func HandleMetricsPost(c *gin.Context) { "memory": req.Memory, "disk": req.Disk, "network": map[string]uint64{ - "bytes_sent": req.Network.BytesSent, - "bytes_received": req.Network.BytesReceived, + "bytes_sent": totalBytesSent, + "bytes_received": totalBytesReceived, }, + "network_interfaces": req.Network, } broadcastMetricsUpdate(deviceID, metrics) } @@ -440,15 +470,61 @@ func GetNetworkMetrics(c *gin.Context) { receivedPoints = []storage.MetricPoint{} } - // 处理数据,传递interval、startTime和endTime参数 - processedSentData := ProcessMetrics(sentPoints, aggregation, interval, startTime, endTime) - processedReceivedData := ProcessMetrics(receivedPoints, aggregation, interval, startTime, endTime) + // 按网卡名称分组发送和接收的指标 + sentByInterface := make(map[string][]storage.MetricPoint) + receivedByInterface := make(map[string][]storage.MetricPoint) - c.JSON(http.StatusOK, gin.H{ - "data": map[string][]MetricData{ + // 分组发送的网络指标 + for _, point := range sentPoints { + // 获取网卡名称,默认使用"all"表示所有网卡 + interfaceName := point.Tags["interface"] + if interfaceName == "" { + interfaceName = "all" + } + sentByInterface[interfaceName] = append(sentByInterface[interfaceName], point) + } + + // 分组接收的网络指标 + for _, point := range receivedPoints { + // 获取网卡名称,默认使用"all"表示所有网卡 + interfaceName := point.Tags["interface"] + if interfaceName == "" { + interfaceName = "all" + } + receivedByInterface[interfaceName] = append(receivedByInterface[interfaceName], point) + } + + // 处理数据,为每个网卡创建独立的数据集 + result := make(map[string]map[string][]MetricData) + + // 合并所有网卡名称 + allInterfaces := make(map[string]bool) + for iface := range sentByInterface { + allInterfaces[iface] = true + } + for iface := range receivedByInterface { + allInterfaces[iface] = true + } + + // 为每个网卡处理数据 + for iface := range allInterfaces { + // 获取该网卡的发送和接收指标 + ifaceSentPoints := sentByInterface[iface] + ifaceReceivedPoints := receivedByInterface[iface] + + // 处理数据 + processedSentData := ProcessMetrics(ifaceSentPoints, aggregation, interval, startTime, endTime) + processedReceivedData := ProcessMetrics(ifaceReceivedPoints, aggregation, interval, startTime, endTime) + + // 保存结果 + result[iface] = map[string][]MetricData{ "sent": processedSentData, "received": processedReceivedData, - }, + } + } + + c.JSON(http.StatusOK, gin.H{ + "data": result, }) } diff --git a/backend/monitor-server b/backend/monitor-server index 23aefef..6a748ea 100755 Binary files a/backend/monitor-server and b/backend/monitor-server differ diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 18b4091..af9fa78 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -1349,11 +1349,25 @@ function updateStatusCards(metrics) { } else if (typeof displayMetrics.network === 'object' && displayMetrics.network.bytes_sent !== undefined && displayMetrics.network.bytes_received !== undefined) { - // WebSocket消息格式 + // WebSocket消息格式 - 总流量 sentRate = displayMetrics.network.bytes_sent; receivedRate = displayMetrics.network.bytes_received; sentTotal = displayMetrics.network.bytes_sent_total || sentRate; receivedTotal = displayMetrics.network.bytes_received_total || receivedRate; + } else if (typeof displayMetrics.network === 'object' && !Array.isArray(displayMetrics.network)) { + // 按网卡分组的数据,计算总流量 + for (const iface in displayMetrics.network) { + const ifaceMetrics = displayMetrics.network[iface]; + if (ifaceMetrics.bytes_sent !== undefined && ifaceMetrics.bytes_received !== undefined) { + sentRate += ifaceMetrics.bytes_sent; + receivedRate += ifaceMetrics.bytes_received; + sentTotal += ifaceMetrics.bytes_sent_total || ifaceMetrics.bytes_sent; + receivedTotal += ifaceMetrics.bytes_received_total || ifaceMetrics.bytes_received; + } else if (ifaceMetrics.BytesSent !== undefined && ifaceMetrics.BytesReceived !== undefined) { + sentRate += ifaceMetrics.BytesSent; + receivedRate += ifaceMetrics.BytesReceived; + } + } } // 计算比率 @@ -1590,92 +1604,223 @@ function updateCharts(cpuData, memoryData, diskData, networkData) { charts.disk.update(); } + // 保存当前选中的网卡 + state.currentInterface = state.currentInterface || 'all'; + // 更新网络流量趋势图表(发送总和和接收总和) - if (networkData && networkData.sent && networkData.received && charts.network) { - // 计算发送总和(时间段内的累积值) - if (Array.isArray(networkData.sent) && networkData.sent.length > 0) { - // 排序发送数据 - const sortedSent = sortDataByTime(networkData.sent); - - // 计算累积发送总和(MB) - let cumulativeSent = 0; - const sentSumData = sortedSent.map(item => { - // 转换为MB并累积 - const mbValue = item.value / (1024 * 1024); - cumulativeSent += mbValue; - return { - time: item.time, - value: cumulativeSent - }; - }); - - // 使用固定份数X轴数据计算 - const fixedPointsSentSum = getFixedPointsData(sentSumData); - charts.network.data.datasets[0].data = fixedPointsSentSum.map(item => ({ - x: formatTime(item.time), - y: item.value - })); + if (networkData && charts.network) { + let selectedNetworkData = networkData; + + // 如果是按网卡分组的数据,选择当前选中的网卡数据 + if (typeof networkData === 'object' && networkData.sent === undefined && networkData.received === undefined) { + selectedNetworkData = networkData[state.currentInterface] || networkData['all'] || {}; } - // 计算接收总和(时间段内的累积值) - if (Array.isArray(networkData.received) && networkData.received.length > 0) { - // 排序接收数据 - const sortedReceived = sortDataByTime(networkData.received); + if (selectedNetworkData.sent && selectedNetworkData.received) { + // 计算发送总和(时间段内的累积值) + if (Array.isArray(selectedNetworkData.sent) && selectedNetworkData.sent.length > 0) { + // 排序发送数据 + const sortedSent = sortDataByTime(selectedNetworkData.sent); + + // 计算累积发送总和(MB) + let cumulativeSent = 0; + const sentSumData = sortedSent.map(item => { + // 转换为MB并累积 + const mbValue = item.value / (1024 * 1024); + cumulativeSent += mbValue; + return { + time: item.time, + value: cumulativeSent + }; + }); + + // 使用固定份数X轴数据计算 + const fixedPointsSentSum = getFixedPointsData(sentSumData); + charts.network.data.datasets[0].data = fixedPointsSentSum.map(item => ({ + x: formatTime(item.time), + y: item.value + })); + } - // 计算累积接收总和(MB) - let cumulativeReceived = 0; - const receivedSumData = sortedReceived.map(item => { - // 转换为MB并累积 - const mbValue = item.value / (1024 * 1024); - cumulativeReceived += mbValue; - return { - time: item.time, - value: cumulativeReceived - }; - }); + // 计算接收总和(时间段内的累积值) + if (Array.isArray(selectedNetworkData.received) && selectedNetworkData.received.length > 0) { + // 排序接收数据 + const sortedReceived = sortDataByTime(selectedNetworkData.received); + + // 计算累积接收总和(MB) + let cumulativeReceived = 0; + const receivedSumData = sortedReceived.map(item => { + // 转换为MB并累积 + const mbValue = item.value / (1024 * 1024); + cumulativeReceived += mbValue; + return { + time: item.time, + value: cumulativeReceived + }; + }); + + // 使用固定份数X轴数据计算 + const fixedPointsReceivedSum = getFixedPointsData(receivedSumData); + charts.network.data.datasets[1].data = fixedPointsReceivedSum.map(item => ({ + x: formatTime(item.time), + y: item.value + })); + } - // 使用固定份数X轴数据计算 - const fixedPointsReceivedSum = getFixedPointsData(receivedSumData); - charts.network.data.datasets[1].data = fixedPointsReceivedSum.map(item => ({ - x: formatTime(item.time), - y: item.value - })); + charts.network.update(); } - - charts.network.update(); } // 更新网速趋势图表 - if (networkData && networkData.sent && networkData.received && charts.speed) { - // 更新发送流量 - if (Array.isArray(networkData.sent) && networkData.sent.length > 0) { - const sortedData = sortDataByTime(networkData.sent); - // 使用固定份数X轴数据计算 - const fixedPointsData = getFixedPointsData(sortedData); - charts.speed.data.datasets[0].data = fixedPointsData.map(item => ({ - x: formatTime(item.time), - y: item.value / (1024 * 1024) // 转换为MB/s - })); + if (networkData && charts.speed) { + let selectedNetworkData = networkData; + + // 如果是按网卡分组的数据,选择当前选中的网卡数据 + if (typeof networkData === 'object' && networkData.sent === undefined && networkData.received === undefined) { + selectedNetworkData = networkData[state.currentInterface] || networkData['all'] || {}; } - // 更新接收流量 - if (Array.isArray(networkData.received) && networkData.received.length > 0) { - const sortedData = sortDataByTime(networkData.received); - // 使用固定份数X轴数据计算 - const fixedPointsData = getFixedPointsData(sortedData); - charts.speed.data.datasets[1].data = fixedPointsData.map(item => ({ - x: formatTime(item.time), - y: item.value / (1024 * 1024) // 转换为MB/s - })); + if (selectedNetworkData.sent && selectedNetworkData.received) { + // 更新发送流量 + if (Array.isArray(selectedNetworkData.sent) && selectedNetworkData.sent.length > 0) { + const sortedData = sortDataByTime(selectedNetworkData.sent); + // 使用固定份数X轴数据计算 + const fixedPointsData = getFixedPointsData(sortedData); + charts.speed.data.datasets[0].data = fixedPointsData.map(item => ({ + x: formatTime(item.time), + y: item.value / (1024 * 1024) // 转换为MB/s + })); + } + + // 更新接收流量 + if (Array.isArray(selectedNetworkData.received) && selectedNetworkData.received.length > 0) { + const sortedData = sortDataByTime(selectedNetworkData.received); + // 使用固定份数X轴数据计算 + const fixedPointsData = getFixedPointsData(sortedData); + charts.speed.data.datasets[1].data = fixedPointsData.map(item => ({ + x: formatTime(item.time), + y: item.value / (1024 * 1024) // 转换为MB/s + })); + } + + charts.speed.update(); } - - charts.speed.update(); } + // 更新网卡选择下拉框 + updateInterfaceDropdown(networkData); + // 初始化图表(如果尚未初始化) initDetailedCharts(); } +// 更新网卡选择下拉框 +function updateInterfaceDropdown(networkData) { + // 创建或获取网卡选择容器 + let interfaceContainer = document.getElementById('interfaceSelectorContainer'); + if (!interfaceContainer) { + // 获取图表选项卡导航容器 + const chartTabs = document.getElementById('chartTabs'); + if (!chartTabs) { + return; + } + + // 创建网卡选择容器 + interfaceContainer = document.createElement('div'); + interfaceContainer.id = 'interfaceSelectorContainer'; + interfaceContainer.className = 'flex items-center gap-2 ml-4'; + + // 创建标签 + const label = document.createElement('label'); + label.htmlFor = 'interfaceSelector'; + label.className = 'text-sm text-gray-600'; + label.textContent = '网卡:'; + + // 创建下拉框 + const select = document.createElement('select'); + select.id = 'interfaceSelector'; + select.className = 'px-3 py-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm'; + + // 添加默认选项 + const defaultOption = document.createElement('option'); + defaultOption.value = 'all'; + defaultOption.textContent = '所有网卡'; + select.appendChild(defaultOption); + + // 添加事件监听 + select.addEventListener('change', (e) => { + state.currentInterface = e.target.value; + // 重新加载指标 + loadMetrics(); + }); + + // 组装容器 + interfaceContainer.appendChild(label); + interfaceContainer.appendChild(select); + + // 将容器添加到图表选项卡导航中 + const tabsContainer = chartTabs.querySelector('.flex.flex-wrap'); + if (tabsContainer) { + tabsContainer.appendChild(interfaceContainer); + } + } + + // 更新下拉框选项 + const select = document.getElementById('interfaceSelector'); + if (select) { + // 保存当前选中的值 + const currentValue = select.value; + + // 清空现有选项 + select.innerHTML = ''; + + // 添加默认选项 + const defaultOption = document.createElement('option'); + defaultOption.value = 'all'; + defaultOption.textContent = '所有网卡'; + select.appendChild(defaultOption); + + // 添加所有网卡选项 + // 检查是否有按网卡分组的网络数据 + if (typeof networkData === 'object' && networkData.sent === undefined && networkData.received === undefined) { + // 获取所有网卡名称 + const interfaces = Object.keys(networkData); + + // 添加所有网卡选项 + interfaces.forEach(iface => { + // 只添加实际的网卡名称,不添加"all"选项 + if (iface !== 'all') { + const option = document.createElement('option'); + option.value = iface; + option.textContent = iface; + select.appendChild(option); + } + }); + } else { + // 如果没有按网卡分组的数据,使用模拟网卡名称 + // 这里可以根据实际情况修改,比如从其他地方获取网卡名称列表 + const mockInterfaces = ['eth0', 'eth1', 'lo']; + mockInterfaces.forEach(iface => { + const option = document.createElement('option'); + option.value = iface; + option.textContent = iface; + select.appendChild(option); + }); + } + + // 恢复当前选中的值 + select.value = currentValue; + } + + // 检查当前选中的选项卡,如果不是"网络"或"网速",隐藏网卡选择下拉框 + const activeTab = document.querySelector('.chart-tab.active'); + if (activeTab && activeTab.dataset.tab !== 'network' && activeTab.dataset.tab !== 'speed') { + interfaceContainer.classList.add('hidden'); + } else { + interfaceContainer.classList.remove('hidden'); + } +} + // 尝试重连WebSocket function attemptReconnect() { if (wsReconnectAttempts < wsMaxReconnectAttempts) { @@ -2073,6 +2218,17 @@ function initChartTabs() { if (activeContainer) { activeContainer.classList.remove('hidden'); } + + // 显示/隐藏网卡选择下拉框 + const interfaceContainer = document.getElementById('interfaceSelectorContainer'); + if (interfaceContainer) { + // 只有在点击"网络"或"网速"选项卡时,显示网卡选择下拉框 + if (tabId === 'network' || tabId === 'speed') { + interfaceContainer.classList.remove('hidden'); + } else { + interfaceContainer.classList.add('hidden'); + } + } }); }); } diff --git a/test_agent.json b/test_agent.json new file mode 100644 index 0000000..fe4a7e6 --- /dev/null +++ b/test_agent.json @@ -0,0 +1,10 @@ +{ + "server_url": "http://localhost:8080/api", + "id": "test-agent", + "name": "Test Agent", + "device_id": "test-device", + "token": "bb30bfaee01bf7b541bbefe422f72645", + "interval": "5s", + "debug": true, + "api_port": 8081 +} \ No newline at end of file diff --git a/test_metrics.sh b/test_metrics.sh new file mode 100755 index 0000000..9bec916 --- /dev/null +++ b/test_metrics.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# 测试发送单个指标对象 +echo "测试发送单个指标对象:" +curl -v -X POST -H "Content-Type: application/json" -H "X-Device-ID: test-device" -H "X-Agent-Name: test-agent" -H "X-Device-Token: test-token" -d '{"cpu": 50.5, "memory": 30.2, "disk": {":/": 45.6}, "network": {"eth0": {"bytes_sent": 1000, "bytes_received": 2000}}}' http://localhost:8080/api/metrics/ + +echo "\n---\n" + +# 测试发送指标数组 +echo "测试发送指标数组:" +curl -v -X POST -H "Content-Type: application/json" -H "X-Device-ID: test-device" -H "X-Agent-Name: test-agent" -H "X-Device-Token: test-token" -d '[{"cpu": 50.5, "memory": 30.2, "disk": {":/": 45.6}, "network": {"eth0": {"bytes_sent": 1000, "bytes_received": 2000}}}, {"cpu": 60.5, "memory": 40.2, "disk": {":/": 55.6}, "network": {"eth0": {"bytes_sent": 2000, "bytes_received": 3000}}}]' http://localhost:8080/api/metrics/