diff --git a/cmd/agent/main.go b/cmd/agent/main.go index f9cf71f..e383789 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -29,11 +29,13 @@ var ( Run: run, } clientID string + server string clientSecret string debug bool ) func main() { + rootCmd.PersistentFlags().StringVarP(&server, "server", "s", "localhost:5555", "客户端ID") rootCmd.PersistentFlags().StringVarP(&clientID, "id", "i", "", "客户端ID") rootCmd.PersistentFlags().StringVarP(&clientSecret, "secret", "p", "", "客户端Secret") rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "开启Debug") @@ -48,7 +50,6 @@ var reporting bool var client pb.NezhaServiceClient var ctx = context.Background() var delayWhenError = time.Second * 10 -var delayWhenReport = time.Second func run(cmd *cobra.Command, args []string) { dao.Conf = &model.Config{ @@ -67,7 +68,7 @@ func run(cmd *cobra.Command, args []string) { log.Println("Try to reconnect ...") } for { - conn, err = grpc.Dial(":5555", grpc.WithInsecure(), grpc.WithPerRPCCredentials(&auth)) + conn, err = grpc.Dial(server, grpc.WithInsecure(), grpc.WithPerRPCCredentials(&auth)) if err != nil { log.Printf("grpc.Dial err: %v", err) retry() @@ -121,12 +122,12 @@ func reportState() { defer log.Printf("reportState exit %v %v => %v", endReport, time.Now(), err) for { if endReport.After(time.Now()) { - _, err = client.ReportState(ctx, monitor.GetState(0).PB()) + monitor.TrackNetworkSpeed() + _, err = client.ReportState(ctx, monitor.GetState(1).PB()) if err != nil { log.Printf("reportState error %v", err) time.Sleep(delayWhenError) } } - time.Sleep(delayWhenReport) } } diff --git a/cmd/dashboard/controller/controller.go b/cmd/dashboard/controller/controller.go index ff7397d..03bb713 100644 --- a/cmd/dashboard/controller/controller.go +++ b/cmd/dashboard/controller/controller.go @@ -24,12 +24,18 @@ func ServeWeb() { "tf": func(t time.Time) string { return t.Format("2006年1月2号") }, + "stf": func(s uint64) string { + return time.Unix(int64(s), 0).Format("2006年1月2号 15:04") + }, "fs": func() string { if !dao.Conf.Debug { return "" } return fmt.Sprintf("%d", time.Now().UnixNano()) }, + "sf": func(duration uint64) string { + return time.Duration(time.Duration(duration) * time.Second).String() + }, "bf": func(b uint64) string { return bytefmt.ByteSize(b) }, diff --git a/model/monitor.go b/model/monitor.go index e5d2e08..746db7d 100644 --- a/model/monitor.go +++ b/model/monitor.go @@ -10,44 +10,53 @@ const ( // State .. type State struct { - CPU float64 - MemTotal uint64 - MemUsed uint64 - SwapTotal uint64 - SwapUsed uint64 - DiskTotal uint64 - DiskUsed uint64 - NetIn uint64 - NetOut uint64 + CPU float64 + MemTotal uint64 + MemUsed uint64 + SwapTotal uint64 + SwapUsed uint64 + DiskTotal uint64 + DiskUsed uint64 + NetInTransfer uint64 + NetOutTransfer uint64 + NetInSpeed uint64 + NetOutSpeed uint64 + Uptime uint64 } // PB .. func (s *State) PB() *pb.State { return &pb.State{ - Cpu: s.CPU, - MemTotal: s.MemTotal, - MemUsed: s.MemUsed, - SwapTotal: s.SwapTotal, - SwapUsed: s.SwapUsed, - DiskTotal: s.DiskTotal, - DiskUsed: s.DiskUsed, - NetIn: s.NetIn, - NetOut: s.NetOut, + Cpu: s.CPU, + MemTotal: s.MemTotal, + MemUsed: s.MemUsed, + SwapTotal: s.SwapTotal, + SwapUsed: s.SwapUsed, + DiskTotal: s.DiskTotal, + DiskUsed: s.DiskUsed, + NetInTransfer: s.NetInTransfer, + NetOutTransfer: s.NetOutTransfer, + NetInSpeed: s.NetInSpeed, + NetOutSpeed: s.NetOutSpeed, + Uptime: s.Uptime, } } // PB2State .. func PB2State(s *pb.State) State { return State{ - CPU: s.GetCpu(), - MemTotal: s.GetMemTotal(), - MemUsed: s.GetMemUsed(), - SwapTotal: s.GetSwapTotal(), - SwapUsed: s.GetSwapUsed(), - DiskTotal: s.GetDiskTotal(), - DiskUsed: s.GetDiskUsed(), - NetIn: s.GetNetIn(), - NetOut: s.GetNetOut(), + CPU: s.GetCpu(), + MemTotal: s.GetMemTotal(), + MemUsed: s.GetMemUsed(), + SwapTotal: s.GetSwapTotal(), + SwapUsed: s.GetSwapUsed(), + DiskTotal: s.GetDiskTotal(), + DiskUsed: s.GetDiskUsed(), + NetInTransfer: s.GetNetInTransfer(), + NetOutTransfer: s.GetNetOutTransfer(), + NetInSpeed: s.GetNetInSpeed(), + NetOutSpeed: s.GetNetOutSpeed(), + Uptime: s.GetUptime(), } } @@ -58,8 +67,7 @@ type Host struct { CPU []string Arch string Virtualization string - Uptime string - BootTime string + BootTime uint64 IP string CountryCode string Version string @@ -73,7 +81,6 @@ func (h *Host) PB() *pb.Host { Cpu: h.CPU, Arch: h.Arch, Virtualization: h.Virtualization, - Uptime: h.Uptime, BootTime: h.BootTime, Ip: h.IP, CountryCode: h.CountryCode, @@ -89,7 +96,6 @@ func PB2Host(h *pb.Host) Host { CPU: h.GetCpu(), Arch: h.GetArch(), Virtualization: h.GetVirtualization(), - Uptime: h.GetUptime(), BootTime: h.GetBootTime(), IP: h.GetIp(), CountryCode: h.GetCountryCode(), diff --git a/pkg/mygin/mygin.go b/pkg/mygin/mygin.go index 94dd400..033df7a 100644 --- a/pkg/mygin/mygin.go +++ b/pkg/mygin/mygin.go @@ -13,6 +13,7 @@ import ( // CommonEnvironment .. func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H { data["MatchedPath"] = c.MustGet("MatchedPath") + data["Version"] = dao.Version // 站点标题 if t, has := data["Title"]; !has { data["Title"] = dao.Conf.Site.Brand diff --git a/proto/nezha.proto b/proto/nezha.proto index 9ccc509..72fbd73 100644 --- a/proto/nezha.proto +++ b/proto/nezha.proto @@ -14,11 +14,10 @@ message Host { repeated string cpu = 3; string arch = 4; string virtualization = 5; - string uptime = 6; - string boot_time = 7; - string ip = 8; - string country_code = 9; - string version = 10; + uint64 boot_time = 6; + string ip = 7; + string country_code = 8; + string version = 9; } message State { @@ -29,8 +28,11 @@ message State { uint64 swap_used = 5; uint64 disk_total = 6; uint64 disk_used = 7; - uint64 net_in = 8; - uint64 net_out = 9; + uint64 net_in_transfer = 8; + uint64 net_out_transfer = 9; + uint64 net_in_speed = 10; + uint64 net_out_speed = 11; + uint64 uptime = 12; } message Receipt{ diff --git a/resource/template/common/footer.html b/resource/template/common/footer.html index 538feb0..e0ecc84 100644 --- a/resource/template/common/footer.html +++ b/resource/template/common/footer.html @@ -1,7 +1,7 @@ {{define "common/footer"}} diff --git a/resource/template/page/home.html b/resource/template/page/home.html index c38f0d3..1120e8b 100644 --- a/resource/template/page/home.html +++ b/resource/template/page/home.html @@ -11,8 +11,14 @@ class="{{$server.Host.CountryCode}} flag">{{end}}{{$server.Name}}
@@ -25,15 +31,6 @@
-
硬盘
-
-
-
-
-
-
-
内存
+
交换
+
+
+
+
+
+
+
网络
- {{$server.State.NetIn|bf}} - {{$server.State.NetOut|bf}} + {{$server.State.NetInSpeed|bf}}/s + {{$server.State.NetOutSpeed|bf}}/s +
+
硬盘
+
+
+
+
+
+
+
+
在线
+
+ {{$server.State.Uptime|sf}}
diff --git a/service/dao/dao.go b/service/dao/dao.go index 7d31020..5727b0d 100644 --- a/service/dao/dao.go +++ b/service/dao/dao.go @@ -26,3 +26,6 @@ var ServerList map[string]*model.Server // ServerLock .. var ServerLock sync.RWMutex + +// Version .. +var Version = "debug" diff --git a/service/monitor/monitor.go b/service/monitor/monitor.go index fd89fee..a8b46b5 100644 --- a/service/monitor/monitor.go +++ b/service/monitor/monitor.go @@ -15,6 +15,7 @@ import ( "github.com/shirou/gopsutil/net" "github.com/p14yground/nezha/model" + "github.com/p14yground/nezha/service/dao" ) type ipDotSbGeoIP struct { @@ -22,6 +23,8 @@ type ipDotSbGeoIP struct { IP string } +var netInSpeed, netOutSpeed, netInTransfer, netOutTransfer, lastUpdate uint64 + // GetHost .. func GetHost() *model.Host { hi, _ := host.Info() @@ -46,49 +49,80 @@ func GetHost() *model.Host { CPU: cpus, Arch: hi.KernelArch, Virtualization: hi.VirtualizationSystem, - Uptime: fmt.Sprintf("%v", hi.Uptime), - BootTime: fmt.Sprintf("%v", hi.BootTime), + BootTime: hi.BootTime, IP: ip.IP, CountryCode: strings.ToLower(ip.CountryCode), + Version: dao.Version, } } // GetState .. -func GetState(delay uint64) *model.State { +func GetState(delay int64) *model.State { + hi, _ := host.Info() // Memory mv, _ := mem.VirtualMemory() ms, _ := mem.SwapMemory() - // Disk - var diskTotal, diskUsed uint64 - dparts, _ := disk.Partitions(true) - for _, part := range dparts { - u, _ := disk.Usage(part.Mountpoint) - diskTotal += u.Total - diskUsed += u.Used - } // CPU var cpuPercent float64 cp, err := cpu.Percent(time.Second*time.Duration(delay), false) if err == nil { cpuPercent = cp[0] + } + // Disk + var diskTotal, diskUsed uint64 + dparts, _ := disk.Partitions(true) + var lastDevice string + for _, part := range dparts { + u, _ := disk.Usage(part.Mountpoint) + if lastDevice != part.Device { + diskTotal += u.Total + lastDevice = part.Device + } + diskUsed += u.Used + } - } - // Network - var netIn, netOut uint64 - nc, err := net.IOCounters(false) - if err == nil { - netIn = nc[0].BytesRecv - netOut = nc[0].BytesSent - } return &model.State{ - CPU: cpuPercent, - MemTotal: mv.Total, - MemUsed: mv.Used, - SwapTotal: ms.Total, - SwapUsed: ms.Used, - DiskTotal: diskTotal, - DiskUsed: diskUsed, - NetIn: netIn, - NetOut: netOut, + CPU: cpuPercent, + MemTotal: mv.Total, + MemUsed: mv.Used, + SwapTotal: ms.Total, + SwapUsed: ms.Used, + DiskTotal: diskTotal, + DiskUsed: diskUsed, + NetInTransfer: netInTransfer, + NetOutTransfer: netOutTransfer, + NetInSpeed: netInSpeed, + NetOutSpeed: netOutSpeed, + Uptime: hi.Uptime, + } +} + +// TrackNetworkSpeed .. +func TrackNetworkSpeed() { + var innerNetInTransfer, innerNetOutTransfer uint64 + nc, err := net.IOCounters(true) + if err == nil { + for i := 0; i < len(nc); i++ { + if strings.HasPrefix(nc[i].Name, "e") { + innerNetInTransfer += nc[i].BytesRecv + innerNetOutTransfer += nc[i].BytesSent + } + } + if netInTransfer == 0 { + netInTransfer = innerNetInTransfer + } + if netOutTransfer == 0 { + netOutTransfer = innerNetOutTransfer + } + diff := uint64(time.Now().Unix()) + if lastUpdate == 0 { + lastUpdate = diff + return + } + diff -= lastUpdate + if diff > 0 { + netInSpeed = (innerNetInTransfer - netInTransfer) / diff + netOutSpeed = (innerNetOutTransfer - netOutTransfer) / diff + } } }