diff --git a/frontend/src/pages/index/SystemHistoryModal.tsx b/frontend/src/pages/index/SystemHistoryModal.tsx index 9d433278..59be4d05 100644 --- a/frontend/src/pages/index/SystemHistoryModal.tsx +++ b/frontend/src/pages/index/SystemHistoryModal.tsx @@ -3,12 +3,14 @@ import type { ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; import { Modal, Select, Tabs } from 'antd'; import { + ApiOutlined, DashboardOutlined, DatabaseOutlined, DeploymentUnitOutlined, GlobalOutlined, HddOutlined, LineChartOutlined, + PieChartOutlined, TeamOutlined, } from '@ant-design/icons'; @@ -43,11 +45,13 @@ interface MetricDef { } const METRICS: MetricDef[] = [ - { key: 'cpu', tab: 'CPU', title: 'pages.index.historyTitleCpu', icon: , valueMax: 100, unit: '%', stroke: '' }, - { key: 'mem', tab: 'RAM', title: 'pages.index.historyTitleMem', icon: , valueMax: 100, unit: '%', stroke: '#7c4dff' }, + { key: 'cpu', tab: 'CPU', tabKey: 'pages.index.cpu', title: 'pages.index.historyTitleCpu', icon: , valueMax: 100, unit: '%', stroke: '' }, + { key: 'mem', tab: 'RAM', tabKey: 'pages.index.memory', title: 'pages.index.historyTitleMem', icon: , valueMax: 100, unit: '%', stroke: '#7c4dff', key2: 'swap', stroke2: '#ffa940', name1: 'pages.index.memory', name2: 'pages.index.swap' }, { key: 'netUp', tab: 'Bandwidth', tabKey: 'pages.index.historyTabBandwidth', title: 'pages.index.historyTitleNetwork', icon: , valueMax: null, unit: 'B/s', stroke: '#1890ff', key2: 'netDown', stroke2: '#13c2c2', name1: 'Up', name2: 'Down' }, { key: 'pktUp', tab: 'Packets', tabKey: 'pages.index.historyTabPackets', title: 'pages.index.historyTitlePackets', icon: , valueMax: null, unit: 'pkt/s', stroke: '#2f54eb', key2: 'pktDown', stroke2: '#36cfc9', name1: 'Up', name2: 'Down' }, + { key: 'tcpCount', tab: 'Connections', tabKey: 'pages.index.historyTabConnections', title: 'pages.index.historyTitleConnections', icon: , valueMax: null, unit: '', stroke: '#597ef7', key2: 'udpCount', stroke2: '#73d13d', name1: 'TCP', name2: 'UDP' }, { key: 'diskRead', tab: 'Disk I/O', tabKey: 'pages.index.historyTabDisk', title: 'pages.index.historyTitleDisk', icon: , valueMax: null, unit: 'B/s', stroke: '#eb2f96', key2: 'diskWrite', stroke2: '#722ed1', name1: 'Read', name2: 'Write' }, + { key: 'diskUsage', tab: 'Disk Usage', tabKey: 'pages.index.historyTabDiskUsage', title: 'pages.index.historyTitleDiskUsage', icon: , valueMax: 100, unit: '%', stroke: '#13c2c2' }, { key: 'online', tab: 'Online', tabKey: 'pages.index.historyTabOnline', title: 'pages.index.historyTitleOnline', icon: , valueMax: null, unit: '', stroke: '#52c41a' }, { key: 'load1', tab: 'Load', tabKey: 'pages.index.historyTabLoad', title: 'pages.index.historyTitleLoad', icon: , valueMax: null, unit: '', stroke: '#fa8c16', key2: 'load5', stroke2: '#f5222d', name1: '1m', name2: '5m', key3: 'load15', stroke3: '#a0d911', name3: '15m' }, ]; @@ -64,7 +68,9 @@ function unitFormatter(unit: string, activeKey: string): (v: number) => string { } return (v) => { const n = Number(v) || 0; - if (activeKey === 'online') return String(Math.round(n)); + if (activeKey === 'online' || activeKey === 'tcpCount' || activeKey === 'udpCount') { + return Math.round(n).toLocaleString(); + } return n.toFixed(2); }; } @@ -97,6 +103,7 @@ export default function SystemHistoryModal({ open, status, onClose }: SystemHist const [timestamps, setTimestamps] = useState([]); const activeMetric = useMemo(() => METRICS.find((m) => m.key === activeKey), [activeKey]); + const trName = (n?: string) => (n && n.startsWith('pages.') ? t(n) : n); const strokeColor = activeMetric?.stroke || status?.cpu?.color || '#008771'; const yFormatter = useMemo( () => unitFormatter(activeMetric?.unit ?? '', activeKey), @@ -178,6 +185,13 @@ export default function SystemHistoryModal({ open, status, onClose }: SystemHist if (open) fetchBucket(); }, [open, activeKey, bucket, fetchBucket]); + useEffect(() => { + if (!open) return undefined; + const ms = bucket <= 30 ? 2000 : 10000; + const id = window.setInterval(() => fetchBucket(), ms); + return () => window.clearInterval(id); + }, [open, bucket, fetchBucket]); + return ( metricCapacityDefault { + v = v[len(v)-metricCapacityDefault:] + } + h.metrics[k] = v + } +} + // aggregate returns up to maxPoints buckets of size bucketSeconds, // each bucket carrying the arithmetic mean of the underlying samples. // Bucket alignment is to absolute Unix-second boundaries so two @@ -137,7 +171,7 @@ var ( // status sample. Exposed for documentation/test purposes; the // controller validates incoming names against an allow-list. var SystemMetricKeys = []string{ - "cpu", "mem", "netUp", "netDown", "pktUp", "pktDown", "diskRead", "diskWrite", "online", "load1", "load5", "load15", + "cpu", "mem", "swap", "netUp", "netDown", "pktUp", "pktDown", "diskRead", "diskWrite", "diskUsage", "tcpCount", "udpCount", "online", "load1", "load5", "load15", } // NodeMetricKeys lists the per-node metric names NodeHeartbeatJob writes. @@ -150,3 +184,54 @@ var NodeMetricKeys = []string{"cpu", "mem"} var XrayMetricKeys = []string{ "xrAlloc", "xrSys", "xrHeapObjects", "xrNumGC", "xrPauseNs", } + +// systemMetricsStorePath is where the host time-series is persisted between +// restarts. It lives next to the database so a single volume mount carries +// both. Only systemMetrics is persisted — node and xray series are cheap to +// rebuild and tied to live connections. +func systemMetricsStorePath() string { + return filepath.Join(config.GetDBFolderPath(), "system_metrics.gob") +} + +// PersistSystemMetrics writes the host time-series to disk via a temp file + +// rename so a crash mid-write can't corrupt the previous snapshot. Called on a +// timer and at shutdown. +func PersistSystemMetrics() error { + path := systemMetricsStorePath() + tmp := path + ".tmp" + f, err := os.Create(tmp) + if err != nil { + return err + } + if err := gob.NewEncoder(f).Encode(systemMetrics.snapshot()); err != nil { + f.Close() + os.Remove(tmp) + return err + } + if err := f.Close(); err != nil { + os.Remove(tmp) + return err + } + return os.Rename(tmp, path) +} + +// RestoreSystemMetrics loads a previously persisted host time-series on startup. +// A missing file is not an error (first boot). Aggregation already windows by +// time, so any gap from downtime is handled by the readers. +func RestoreSystemMetrics() { + path := systemMetricsStorePath() + f, err := os.Open(path) + if err != nil { + if !os.IsNotExist(err) { + logger.Warning("restore system metrics failed:", err) + } + return + } + defer f.Close() + var data map[string][]MetricSample + if err := gob.NewDecoder(f).Decode(&data); err != nil { + logger.Warning("decode system metrics failed:", err) + return + } + systemMetrics.restore(data) +} diff --git a/web/service/server.go b/web/service/server.go index 08e3a7d4..dcbe5e51 100644 --- a/web/service/server.go +++ b/web/service/server.go @@ -565,12 +565,22 @@ func (s *ServerService) AppendStatusSample(t time.Time, status *Status) { if status.Mem.Total > 0 { systemMetrics.append("mem", t, float64(status.Mem.Current)*100.0/float64(status.Mem.Total)) } + if status.Swap.Total > 0 { + systemMetrics.append("swap", t, float64(status.Swap.Current)*100.0/float64(status.Swap.Total)) + } else { + systemMetrics.append("swap", t, 0) + } systemMetrics.append("netUp", t, float64(status.NetIO.Up)) systemMetrics.append("netDown", t, float64(status.NetIO.Down)) systemMetrics.append("diskRead", t, float64(status.DiskIO.Read)) systemMetrics.append("diskWrite", t, float64(status.DiskIO.Write)) + if status.Disk.Total > 0 { + systemMetrics.append("diskUsage", t, float64(status.Disk.Current)*100.0/float64(status.Disk.Total)) + } systemMetrics.append("pktUp", t, float64(status.NetIO.PktUp)) systemMetrics.append("pktDown", t, float64(status.NetIO.PktDown)) + systemMetrics.append("tcpCount", t, float64(status.TcpCount)) + systemMetrics.append("udpCount", t, float64(status.UdpCount)) online := 0 if p != nil && p.IsRunning() { online = len(p.GetOnlineClients()) diff --git a/web/translation/ar-EG.json b/web/translation/ar-EG.json index 55857ee5..84865320 100644 --- a/web/translation/ar-EG.json +++ b/web/translation/ar-EG.json @@ -128,12 +128,12 @@ }, "index": { "title": "نظرة عامة", - "cpu": "CPU", + "cpu": "المعالج", "logicalProcessors": "المعالجات المنطقية", "frequency": "التردد", - "swap": "Swap", + "swap": "التبديل", "storage": "تخزين", - "memory": "RAM", + "memory": "الذاكرة", "threads": "خيوط", "xrayStatus": "Xray", "stopXray": "إيقاف", @@ -162,11 +162,15 @@ "historyTitleDisk": "إدخال/إخراج القرص", "historyTitleOnline": "العملاء المتصلون", "historyTitleLoad": "متوسط حمل النظام (1 / 5 / 15 دقيقة)", + "historyTitleConnections": "الاتصالات النشطة (TCP / UDP)", + "historyTitleDiskUsage": "استخدام مساحة القرص", "historyTabBandwidth": "عرض النطاق", "historyTabPackets": "الحزم", - "historyTabDisk": "Disk I/O", + "historyTabDisk": "قرص I/O", "historyTabOnline": "متصل", "historyTabLoad": "الحِمل", + "historyTabConnections": "الاتصالات", + "historyTabDiskUsage": "استخدام القرص", "charts": "الرسوم البيانية", "xrayMetricsTitle": "مقاييس Xray", "xrayTitleHeap": "ذاكرة الكومة المخصصة", diff --git a/web/translation/en-US.json b/web/translation/en-US.json index b94532ec..34b67d3b 100644 --- a/web/translation/en-US.json +++ b/web/translation/en-US.json @@ -162,11 +162,15 @@ "historyTitleDisk": "Disk I/O", "historyTitleOnline": "Online Clients", "historyTitleLoad": "System Load Average (1m / 5m / 15m)", + "historyTitleConnections": "Active Connections (TCP / UDP)", + "historyTitleDiskUsage": "Disk Space Usage", "historyTabBandwidth": "Bandwidth", "historyTabPackets": "Packets", "historyTabDisk": "Disk I/O", "historyTabOnline": "Online", "historyTabLoad": "Load", + "historyTabConnections": "Connections", + "historyTabDiskUsage": "Disk Usage", "charts": "Charts", "xrayMetricsTitle": "Xray Metrics", "xrayTitleHeap": "Allocated Heap Memory", diff --git a/web/translation/es-ES.json b/web/translation/es-ES.json index 2436a6c5..4d757f01 100644 --- a/web/translation/es-ES.json +++ b/web/translation/es-ES.json @@ -133,7 +133,7 @@ "frequency": "Frecuencia", "swap": "Swap", "storage": "Almacenamiento", - "memory": "RAM", + "memory": "Memoria", "threads": "Hilos", "xrayStatus": "Xray", "stopXray": "Detener", @@ -162,11 +162,15 @@ "historyTitleDisk": "E/S de Disco", "historyTitleOnline": "Clientes en Línea", "historyTitleLoad": "Carga Media del Sistema (1 / 5 / 15 min)", + "historyTitleConnections": "Conexiones Activas (TCP / UDP)", + "historyTitleDiskUsage": "Uso del Espacio en Disco", "historyTabBandwidth": "Ancho de Banda", "historyTabPackets": "Paquetes", "historyTabDisk": "Disco I/O", "historyTabOnline": "En línea", "historyTabLoad": "Carga", + "historyTabConnections": "Conexiones", + "historyTabDiskUsage": "Uso de Disco", "charts": "Gráficos", "xrayMetricsTitle": "Métricas de Xray", "xrayTitleHeap": "Memoria Heap Asignada", diff --git a/web/translation/fa-IR.json b/web/translation/fa-IR.json index 131abe31..e316ec33 100644 --- a/web/translation/fa-IR.json +++ b/web/translation/fa-IR.json @@ -128,12 +128,12 @@ }, "index": { "title": "نمای کلی", - "cpu": "CPU", + "cpu": "پردازنده", "logicalProcessors": "پردازنده‌های منطقی", "frequency": "فرکانس", - "swap": "Swap", + "swap": "سواپ", "storage": "ذخیره‌سازی", - "memory": "RAM", + "memory": "حافظه", "threads": "نخ‌ها", "xrayStatus": "Xray", "stopXray": "توقف", @@ -162,11 +162,15 @@ "historyTitleDisk": "ورودی/خروجی دیسک", "historyTitleOnline": "کاربران آنلاین", "historyTitleLoad": "میانگین بار سیستم (۱ / ۵ / ۱۵ دقیقه)", + "historyTitleConnections": "اتصالات فعال (TCP / UDP)", + "historyTitleDiskUsage": "مصرف فضای دیسک", "historyTabBandwidth": "پهنای باند", "historyTabPackets": "بسته‌ها", - "historyTabDisk": "Disk I/O", + "historyTabDisk": "دیسک I/O", "historyTabOnline": "آنلاین", "historyTabLoad": "بار", + "historyTabConnections": "اتصالات", + "historyTabDiskUsage": "مصرف دیسک", "charts": "نمودارها", "xrayMetricsTitle": "متریک‌های Xray", "xrayTitleHeap": "حافظه‌ی Heap تخصیص‌یافته", diff --git a/web/translation/id-ID.json b/web/translation/id-ID.json index 36c6b700..eb3dcc38 100644 --- a/web/translation/id-ID.json +++ b/web/translation/id-ID.json @@ -133,7 +133,7 @@ "frequency": "Frekuensi", "swap": "Swap", "storage": "Penyimpanan", - "memory": "RAM", + "memory": "Memori", "threads": "Thread", "xrayStatus": "Xray", "stopXray": "Hentikan", @@ -162,11 +162,15 @@ "historyTitleDisk": "I/O Disk", "historyTitleOnline": "Klien Online", "historyTitleLoad": "Rata-rata Beban Sistem (1 / 5 / 15 mnt)", + "historyTitleConnections": "Koneksi Aktif (TCP / UDP)", + "historyTitleDiskUsage": "Penggunaan Ruang Disk", "historyTabBandwidth": "Bandwidth", "historyTabPackets": "Paket", "historyTabDisk": "Disk I/O", "historyTabOnline": "Online", "historyTabLoad": "Beban", + "historyTabConnections": "Koneksi", + "historyTabDiskUsage": "Penggunaan Disk", "charts": "Grafik", "xrayMetricsTitle": "Metrik Xray", "xrayTitleHeap": "Memori Heap Teralokasi", diff --git a/web/translation/ja-JP.json b/web/translation/ja-JP.json index 89eafa42..3d2e6217 100644 --- a/web/translation/ja-JP.json +++ b/web/translation/ja-JP.json @@ -131,9 +131,9 @@ "cpu": "CPU", "logicalProcessors": "論理プロセッサ", "frequency": "周波数", - "swap": "Swap", + "swap": "スワップ", "storage": "ストレージ", - "memory": "RAM", + "memory": "メモリ", "threads": "スレッド", "xrayStatus": "Xray", "stopXray": "停止", @@ -162,11 +162,15 @@ "historyTitleDisk": "ディスク I/O", "historyTitleOnline": "オンラインクライアント", "historyTitleLoad": "システム平均負荷(1分 / 5分 / 15分)", + "historyTitleConnections": "アクティブな接続 (TCP / UDP)", + "historyTitleDiskUsage": "ディスク使用率", "historyTabBandwidth": "帯域幅", "historyTabPackets": "パケット", "historyTabDisk": "ディスク I/O", "historyTabOnline": "オンライン", "historyTabLoad": "負荷", + "historyTabConnections": "接続数", + "historyTabDiskUsage": "ディスク使用量", "charts": "チャート", "xrayMetricsTitle": "Xray メトリクス", "xrayTitleHeap": "割り当て済みヒープメモリ", diff --git a/web/translation/pt-BR.json b/web/translation/pt-BR.json index 0a358ee7..2f0540e7 100644 --- a/web/translation/pt-BR.json +++ b/web/translation/pt-BR.json @@ -133,7 +133,7 @@ "frequency": "Frequência", "swap": "Swap", "storage": "Armazenamento", - "memory": "RAM", + "memory": "Memória", "threads": "Threads", "xrayStatus": "Xray", "stopXray": "Parar", @@ -162,11 +162,15 @@ "historyTitleDisk": "E/S de Disco", "historyTitleOnline": "Clientes Online", "historyTitleLoad": "Média de Carga do Sistema (1 / 5 / 15 min)", + "historyTitleConnections": "Conexões Ativas (TCP / UDP)", + "historyTitleDiskUsage": "Uso do Espaço em Disco", "historyTabBandwidth": "Largura de Banda", "historyTabPackets": "Pacotes", "historyTabDisk": "Disco I/O", "historyTabOnline": "Online", "historyTabLoad": "Carga", + "historyTabConnections": "Conexões", + "historyTabDiskUsage": "Uso de Disco", "charts": "Gráficos", "xrayMetricsTitle": "Métricas do Xray", "xrayTitleHeap": "Memória Heap Alocada", diff --git a/web/translation/ru-RU.json b/web/translation/ru-RU.json index 6cc088bc..43d341b1 100644 --- a/web/translation/ru-RU.json +++ b/web/translation/ru-RU.json @@ -128,12 +128,12 @@ }, "index": { "title": "Дашборд", - "cpu": "CPU", + "cpu": "ЦП", "logicalProcessors": "Логические процессоры", "frequency": "Частота", - "swap": "Swap", + "swap": "Подкачка", "storage": "Диск", - "memory": "RAM", + "memory": "Память", "threads": "Потоки", "xrayStatus": "Xray", "stopXray": "Стоп", @@ -162,11 +162,15 @@ "historyTitleDisk": "Дисковый ввод-вывод", "historyTitleOnline": "Клиенты онлайн", "historyTitleLoad": "Средняя нагрузка системы (1 / 5 / 15 мин)", + "historyTitleConnections": "Активные соединения (TCP / UDP)", + "historyTitleDiskUsage": "Использование дискового пространства", "historyTabBandwidth": "Пропускная способность", "historyTabPackets": "Пакеты", "historyTabDisk": "Диск I/O", "historyTabOnline": "Онлайн", "historyTabLoad": "Нагрузка", + "historyTabConnections": "Соединения", + "historyTabDiskUsage": "Использование диска", "charts": "Графики", "xrayMetricsTitle": "Метрики Xray", "xrayTitleHeap": "Выделенная память кучи", diff --git a/web/translation/tr-TR.json b/web/translation/tr-TR.json index 7099e7c9..d3c1a084 100644 --- a/web/translation/tr-TR.json +++ b/web/translation/tr-TR.json @@ -131,9 +131,9 @@ "cpu": "CPU", "logicalProcessors": "Mantıksal işlemciler", "frequency": "Frekans", - "swap": "Swap", + "swap": "Takas", "storage": "Depolama", - "memory": "RAM", + "memory": "Bellek", "threads": "İş parçacığı", "xrayStatus": "Xray", "stopXray": "Durdur", @@ -162,11 +162,15 @@ "historyTitleDisk": "Disk G/Ç", "historyTitleOnline": "Çevrimiçi İstemciler", "historyTitleLoad": "Sistem Yük Ortalaması (1d / 5d / 15d)", + "historyTitleConnections": "Etkin Bağlantılar (TCP / UDP)", + "historyTitleDiskUsage": "Disk Alanı Kullanımı", "historyTabBandwidth": "Bant Genişliği", "historyTabPackets": "Paketler", "historyTabDisk": "Disk G/Ç", "historyTabOnline": "Çevrimiçi", "historyTabLoad": "Yük", + "historyTabConnections": "Bağlantılar", + "historyTabDiskUsage": "Disk Kullanımı", "charts": "Grafikler", "xrayMetricsTitle": "Xray Metrikleri", "xrayTitleHeap": "Ayrılan Yığın Belleği", diff --git a/web/translation/uk-UA.json b/web/translation/uk-UA.json index dad37697..a86ffbe5 100644 --- a/web/translation/uk-UA.json +++ b/web/translation/uk-UA.json @@ -128,12 +128,12 @@ }, "index": { "title": "Огляд", - "cpu": "CPU", + "cpu": "ЦП", "logicalProcessors": "Логічні процесори", "frequency": "Частота", - "swap": "Swap", + "swap": "Підкачка", "storage": "Сховище", - "memory": "RAM", + "memory": "Пам’ять", "threads": "Потоки", "xrayStatus": "Xray", "stopXray": "Стоп", @@ -162,11 +162,15 @@ "historyTitleDisk": "Дисковий ввід-вивід", "historyTitleOnline": "Клієнти онлайн", "historyTitleLoad": "Середнє навантаження системи (1 / 5 / 15 хв)", + "historyTitleConnections": "Активні з’єднання (TCP / UDP)", + "historyTitleDiskUsage": "Використання дискового простору", "historyTabBandwidth": "Пропускна здатність", "historyTabPackets": "Пакети", "historyTabDisk": "Диск I/O", "historyTabOnline": "Онлайн", "historyTabLoad": "Навантаження", + "historyTabConnections": "З’єднання", + "historyTabDiskUsage": "Використання диска", "charts": "Графіки", "xrayMetricsTitle": "Метрики Xray", "xrayTitleHeap": "Виділена пам’ять купи", diff --git a/web/translation/vi-VN.json b/web/translation/vi-VN.json index c30dfa14..1daf4967 100644 --- a/web/translation/vi-VN.json +++ b/web/translation/vi-VN.json @@ -133,7 +133,7 @@ "frequency": "Tần số", "swap": "Swap", "storage": "Lưu trữ", - "memory": "RAM", + "memory": "Bộ nhớ", "threads": "Luồng", "xrayStatus": "Xray", "stopXray": "Dừng", @@ -162,11 +162,15 @@ "historyTitleDisk": "I/O đĩa", "historyTitleOnline": "Máy khách trực tuyến", "historyTitleLoad": "Tải trung bình hệ thống (1 / 5 / 15 phút)", + "historyTitleConnections": "Kết nối đang hoạt động (TCP / UDP)", + "historyTitleDiskUsage": "Sử dụng dung lượng đĩa", "historyTabBandwidth": "Băng thông", "historyTabPackets": "Gói tin", "historyTabDisk": "Đĩa I/O", "historyTabOnline": "Trực tuyến", "historyTabLoad": "Tải", + "historyTabConnections": "Kết nối", + "historyTabDiskUsage": "Sử dụng đĩa", "charts": "Biểu đồ", "xrayMetricsTitle": "Chỉ số Xray", "xrayTitleHeap": "Bộ nhớ Heap đã cấp phát", diff --git a/web/translation/zh-CN.json b/web/translation/zh-CN.json index 66523b22..0e0f6295 100644 --- a/web/translation/zh-CN.json +++ b/web/translation/zh-CN.json @@ -131,9 +131,9 @@ "cpu": "CPU", "logicalProcessors": "逻辑处理器", "frequency": "频率", - "swap": "Swap", + "swap": "交换空间", "storage": "存储", - "memory": "RAM", + "memory": "内存", "threads": "线程", "xrayStatus": "Xray", "stopXray": "停止", @@ -162,11 +162,15 @@ "historyTitleDisk": "磁盘 I/O", "historyTitleOnline": "在线客户端", "historyTitleLoad": "系统平均负载(1 分钟 / 5 分钟 / 15 分钟)", + "historyTitleConnections": "活动连接 (TCP / UDP)", + "historyTitleDiskUsage": "磁盘空间使用率", "historyTabBandwidth": "带宽", "historyTabPackets": "数据包", "historyTabDisk": "磁盘 I/O", "historyTabOnline": "在线", "historyTabLoad": "负载", + "historyTabConnections": "连接数", + "historyTabDiskUsage": "磁盘使用量", "charts": "图表", "xrayMetricsTitle": "Xray 指标", "xrayTitleHeap": "已分配的堆内存", diff --git a/web/translation/zh-TW.json b/web/translation/zh-TW.json index abe72197..9aed7b5e 100644 --- a/web/translation/zh-TW.json +++ b/web/translation/zh-TW.json @@ -131,9 +131,9 @@ "cpu": "CPU", "logicalProcessors": "邏輯處理器", "frequency": "頻率", - "swap": "Swap", + "swap": "交換空間", "storage": "儲存", - "memory": "RAM", + "memory": "記憶體", "threads": "執行緒", "xrayStatus": "Xray", "stopXray": "停止", @@ -162,11 +162,15 @@ "historyTitleDisk": "磁碟 I/O", "historyTitleOnline": "線上用戶端", "historyTitleLoad": "系統平均負載(1 分鐘 / 5 分鐘 / 15 分鐘)", + "historyTitleConnections": "使用中的連線 (TCP / UDP)", + "historyTitleDiskUsage": "磁碟空間使用率", "historyTabBandwidth": "頻寬", "historyTabPackets": "封包", "historyTabDisk": "磁碟 I/O", "historyTabOnline": "線上", "historyTabLoad": "負載", + "historyTabConnections": "連線數", + "historyTabDiskUsage": "磁碟使用量", "charts": "圖表", "xrayMetricsTitle": "Xray 指標", "xrayTitleHeap": "已配置的堆積記憶體", diff --git a/web/web.go b/web/web.go index ca990a3e..c4caa596 100644 --- a/web/web.go +++ b/web/web.go @@ -469,6 +469,9 @@ func (s *Server) stop(stopXray bool, stopTgBot bool) error { if s.cron != nil { s.cron.Stop() } + if err := service.PersistSystemMetrics(); err != nil { + logger.Warning("persist system metrics on shutdown failed:", err) + } if stopXray { service.StopTrafficWriter() }