diff --git a/go.mod b/go.mod
index ce29f53..92942ba 100644
--- a/go.mod
+++ b/go.mod
@@ -72,6 +72,7 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect
+ github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/viper v1.21.0 // indirect
diff --git a/go.sum b/go.sum
index a6e703e..0dd1304 100644
--- a/go.sum
+++ b/go.sum
@@ -149,6 +149,8 @@ github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88ee
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY=
github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
+github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
+github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
diff --git a/pkg/agent/service/agent.go b/pkg/agent/service/agent.go
index 4cfa179..317b7a9 100644
--- a/pkg/agent/service/agent.go
+++ b/pkg/agent/service/agent.go
@@ -21,6 +21,7 @@ import (
"github.com/dushixiang/pika/pkg/version"
"github.com/gorilla/websocket"
"github.com/jpillora/backoff"
+ "github.com/sourcegraph/conc"
)
// 定义特殊错误类型
@@ -193,35 +194,36 @@ func (a *Agent) runOnce(ctx context.Context, onConnected func()) error {
done := make(chan struct{})
errChan := make(chan error, 3)
+ var wg conc.WaitGroup
// 启动读取循环(处理服务端的 Ping/Pong 等控制消息)
- go func() {
+ wg.Go(func() {
if err := a.readLoop(rawConn, done); err != nil {
errChan <- fmt.Errorf("读取失败: %w", err)
}
- }()
+ })
// 启动心跳和数据发送
- go func() {
+ wg.Go(func() {
if err := a.heartbeatLoop(ctx, conn, done); err != nil {
errChan <- fmt.Errorf("心跳失败: %w", err)
}
- }()
+ })
- go func() {
+ wg.Go(func() {
if err := a.metricsLoop(ctx, conn, collectorManager, done); err != nil {
errChan <- fmt.Errorf("数据采集失败: %w", err)
}
- }()
+ })
// 启动防篡改事件监控
- go func() {
+ wg.Go(func() {
a.tamperEventLoop(ctx, conn, done)
- }()
+ })
// 启动防篡改属性告警监控
- go func() {
+ wg.Go(func() {
a.tamperAlertLoop(ctx, conn, done)
- }()
+ })
// 等待错误或上下文取消
select {
diff --git a/web/src/components/PublicHeader.tsx b/web/src/components/PublicHeader.tsx
index f7ad674..68aa441 100644
--- a/web/src/components/PublicHeader.tsx
+++ b/web/src/components/PublicHeader.tsx
@@ -63,10 +63,10 @@ const PublicHeader = () => {
- {window.SystemConfig?.SystemNameZh}
+ {window.SystemConfig?.SystemNameEn}
- {window.SystemConfig?.SystemNameEn}
+ {window.SystemConfig?.SystemNameZh}
diff --git a/web/src/components/monitor/ResponseTimeChart.tsx b/web/src/components/monitor/ResponseTimeChart.tsx
index 9f92f0f..c15e69d 100644
--- a/web/src/components/monitor/ResponseTimeChart.tsx
+++ b/web/src/components/monitor/ResponseTimeChart.tsx
@@ -116,7 +116,7 @@ export const ResponseTimeChart = ({monitorId, monitorStats}: ResponseTimeChartPr
if (!historyData?.series) return [];
// 过滤出响应时间指标的 series
- const responseTimeSeries = historyData.series.filter(s => s.name === 'response_time');
+ const responseTimeSeries = historyData.series?.filter(s => s.name === 'response_time');
// 根据选择的探针过滤(使用 agent_name,如果没有则fallback到 agent_id)
const filteredSeries = selectedAgent === 'all'
diff --git a/web/src/components/server/charts/CpuChart.tsx b/web/src/components/server/charts/CpuChart.tsx
index 01ff0e9..fc20cdb 100644
--- a/web/src/components/server/charts/CpuChart.tsx
+++ b/web/src/components/server/charts/CpuChart.tsx
@@ -23,7 +23,7 @@ export const CpuChart = ({agentId, timeRange}: CpuChartProps) => {
// 数据转换
const chartData = useMemo(() => {
- const cpuSeries = metricsResponse?.data.series.find(s => s.name === 'usage');
+ const cpuSeries = metricsResponse?.data.series?.find(s => s.name === 'usage');
if (!cpuSeries) return [];
return cpuSeries.data.map((point) => ({
diff --git a/web/src/components/server/charts/DiskIOChart.tsx b/web/src/components/server/charts/DiskIOChart.tsx
index e27e8f9..4932eda 100644
--- a/web/src/components/server/charts/DiskIOChart.tsx
+++ b/web/src/components/server/charts/DiskIOChart.tsx
@@ -23,10 +23,10 @@ export const DiskIOChart = ({agentId, timeRange}: DiskIOChartProps) => {
// 数据转换
const chartData = useMemo(() => {
- if (!metricsResponse?.data.series || metricsResponse.data.series.length === 0) return [];
+ if (!metricsResponse?.data.series || metricsResponse.data.series?.length === 0) return [];
- const readSeries = metricsResponse.data.series.find(s => s.name === 'read');
- const writeSeries = metricsResponse.data.series.find(s => s.name === 'write');
+ const readSeries = metricsResponse.data.series?.find(s => s.name === 'read');
+ const writeSeries = metricsResponse.data.series?.find(s => s.name === 'write');
if (!readSeries || !writeSeries) return [];
diff --git a/web/src/components/server/charts/GpuChart.tsx b/web/src/components/server/charts/GpuChart.tsx
index 4b8aba2..bf2bff7 100644
--- a/web/src/components/server/charts/GpuChart.tsx
+++ b/web/src/components/server/charts/GpuChart.tsx
@@ -24,13 +24,13 @@ export const GpuChart = ({agentId, timeRange}: GpuChartProps) => {
// 数据转换
const chartData = useMemo(() => {
- if (!metricsResponse?.data.series || metricsResponse.data.series.length === 0) return [];
+ if (!metricsResponse?.data.series || metricsResponse.data.series?.length === 0) return [];
// 按时间戳聚合利用率和温度系列
const timeMap = new Map();
- const utilizationSeries = metricsResponse.data.series.find(s => s.name === 'utilization');
- const temperatureSeries = metricsResponse.data.series.find(s => s.name === 'temperature');
+ const utilizationSeries = metricsResponse.data.series?.find(s => s.name === 'utilization');
+ const temperatureSeries = metricsResponse.data.series?.find(s => s.name === 'temperature');
// 添加利用率数据
utilizationSeries?.data.forEach(point => {
diff --git a/web/src/components/server/charts/MemoryChart.tsx b/web/src/components/server/charts/MemoryChart.tsx
index 2c5159a..ca644b8 100644
--- a/web/src/components/server/charts/MemoryChart.tsx
+++ b/web/src/components/server/charts/MemoryChart.tsx
@@ -23,7 +23,7 @@ export const MemoryChart = ({agentId, timeRange}: MemoryChartProps) => {
// 数据转换
const chartData = useMemo(() => {
- const memorySeries = metricsResponse?.data.series.find(s => s.name === 'usage');
+ const memorySeries = metricsResponse?.data.series?.find(s => s.name === 'usage');
if (!memorySeries) return [];
return memorySeries.data.map((point) => ({
diff --git a/web/src/components/server/charts/NetworkChart.tsx b/web/src/components/server/charts/NetworkChart.tsx
index b3550c8..fafc604 100644
--- a/web/src/components/server/charts/NetworkChart.tsx
+++ b/web/src/components/server/charts/NetworkChart.tsx
@@ -41,10 +41,10 @@ export const NetworkChart = ({agentId, timeRange}: NetworkChartProps) => {
// 数据转换
const chartData = useMemo(() => {
- if (!metricsResponse?.data.series || metricsResponse.data.series.length === 0) return [];
+ if (!metricsResponse?.data.series || metricsResponse.data.series?.length === 0) return [];
- const uploadSeries = metricsResponse.data.series.find(s => s.name === 'upload');
- const downloadSeries = metricsResponse.data.series.find(s => s.name === 'download');
+ const uploadSeries = metricsResponse.data.series?.find(s => s.name === 'upload');
+ const downloadSeries = metricsResponse.data.series?.find(s => s.name === 'download');
if (!uploadSeries || !downloadSeries) return [];
diff --git a/web/src/components/server/charts/NetworkConnectionChart.tsx b/web/src/components/server/charts/NetworkConnectionChart.tsx
index c56bfad..76f3b0b 100644
--- a/web/src/components/server/charts/NetworkConnectionChart.tsx
+++ b/web/src/components/server/charts/NetworkConnectionChart.tsx
@@ -23,12 +23,12 @@ export const NetworkConnectionChart = ({agentId, timeRange}: NetworkConnectionCh
// 数据转换
const chartData = useMemo(() => {
- if (!metricsResponse?.data.series || metricsResponse.data.series.length === 0) return [];
+ if (!metricsResponse?.data.series || metricsResponse.data.series?.length === 0) return [];
// 按时间戳聚合所有连接状态系列
const timeMap = new Map();
- metricsResponse.data.series.forEach(series => {
+ metricsResponse.data.series?.forEach(series => {
const stateName = series.name; // established, time_wait, close_wait, listen
series.data.forEach(point => {
const time = new Date(point.timestamp).toLocaleTimeString('zh-CN', {
diff --git a/web/src/components/server/charts/TemperatureChart.tsx b/web/src/components/server/charts/TemperatureChart.tsx
index b08d6f3..8108074 100644
--- a/web/src/components/server/charts/TemperatureChart.tsx
+++ b/web/src/components/server/charts/TemperatureChart.tsx
@@ -27,12 +27,12 @@ export const TemperatureChart = ({agentId, timeRange}: TemperatureChartProps) =>
// 数据转换
const chartData = useMemo(() => {
- if (!metricsResponse?.data.series || metricsResponse.data.series.length === 0) return [];
+ if (!metricsResponse?.data.series || metricsResponse.data.series?.length === 0) return [];
// 按时间戳聚合所有温度系列
const timeMap = new Map();
- metricsResponse.data.series.forEach(series => {
+ metricsResponse.data.series?.forEach(series => {
const sensorName = series.name; // 使用系列名称作为传感器标识
series.data.forEach(point => {
const time = new Date(point.timestamp).toLocaleTimeString('zh-CN', {
@@ -54,7 +54,7 @@ export const TemperatureChart = ({agentId, timeRange}: TemperatureChartProps) =>
// 提取所有唯一的温度类型
const temperatureTypes = useMemo(() => {
- return metricsResponse?.data.series.map(s => s.name).sort() || [];
+ return metricsResponse?.data.series?.map(s => s.name).sort() || [];
}, [metricsResponse]);
// 根据选中的类型过滤温度数据
diff --git a/web/src/pages/Public/MonitorList.tsx b/web/src/pages/Public/MonitorList.tsx
index e7759a2..859fb9b 100644
--- a/web/src/pages/Public/MonitorList.tsx
+++ b/web/src/pages/Public/MonitorList.tsx
@@ -80,13 +80,13 @@ const MonitorCard = ({monitor, displayMode, onClick}: {
// 将 VictoriaMetrics 的时序数据转换为图表数据
const chartData = useMemo(() => {
- if (!historyData || !historyData.series || historyData.series.length === 0) {
+ if (!historyData || !historyData.series || historyData.series?.length === 0) {
return [];
}
const timeMap = new Map();
- historyData.series.forEach(series => {
+ historyData.series?.forEach(series => {
if (series.data && series.data.length > 0) {
series.data.forEach(point => {
if (!timeMap.has(point.timestamp)) {