浏览代码

use goroutine to record cpu usage

0xJacky 3 年之前
父节点
当前提交
897c3cddcd

+ 9 - 0
frontend/src/api/analytic.js

@@ -0,0 +1,9 @@
+import http from '@/lib/http'
+
+const analytic = {
+    cpu_usage() {
+        return http.get('/analytic/cpu')
+    }
+}
+
+export default analytic

+ 3 - 1
frontend/src/api/index.js

@@ -3,11 +3,13 @@ import config from './config'
 import auth from './auth'
 import user from './user'
 import install from './install'
+import analytic from './analytic'
 
 export default {
     domain,
     config,
     auth,
     user,
-    install
+    install,
+    analytic
 }

+ 13 - 8
frontend/src/views/dashboard/DashBoard.vue

@@ -10,10 +10,16 @@
                                     <span>%</span>
                                 </template>
                             </a-statistic>
-                            <p><translate>Uptime</translate> {{ uptime }}</p>
-                            <p><translate>Load Averages: </translate> 1min:{{ loadavg?.load1?.toFixed(2) }} |
+                            <p>
+                                <translate>Uptime</translate>
+                                {{ uptime }}
+                            </p>
+                            <p>
+                                <translate>Load Averages:</translate>
+                                1min:{{ loadavg?.load1?.toFixed(2) }} |
                                 5min:{{ loadavg?.load5?.toFixed(2) }} |
-                                15min:{{ loadavg?.load15?.toFixed(2) }}</p>
+                                15min:{{ loadavg?.load15?.toFixed(2) }}
+                            </p>
                             <line-chart :chart-data="cpu_analytic" :options="cpu_analytic.options" :height="150"/>
                         </a-col>
                         <a-col :lg="6" :sm="8" :xs="12" class="chart_dashboard">
@@ -120,11 +126,10 @@ export default {
             + btoa(this.$store.state.user.token))
         this.websocket.onmessage = this.wsOnMessage
         this.websocket.onopen = this.wsOpen
-        const time = new Date()
-        for (let i = 200; i > 0; i--) {
-            this.cpu_analytic.datasets[0].data.push({x: time-i*1000, y: 0})
-            this.cpu_analytic.datasets[1].data.push({x: time-i*1000, y: 0})
-        }
+        this.$api.analytic.cpu_usage().then(r => {
+            this.cpu_analytic.datasets[0].data.concat(r.user)
+            this.cpu_analytic.datasets[1].data.concat(r.total)
+        })
     },
     destroyed() {
         this.websocket.close()

+ 55 - 54
main.go

@@ -1,71 +1,72 @@
 package main
 
 import (
-    "context"
-    "flag"
-    "github.com/0xJacky/Nginx-UI/server/model"
-    "github.com/0xJacky/Nginx-UI/server/router"
-    "github.com/0xJacky/Nginx-UI/server/settings"
-    tool2 "github.com/0xJacky/Nginx-UI/server/tool"
-    "github.com/gin-gonic/gin"
-    "log"
-    "mime"
-    "net/http"
-    "os/signal"
-    "syscall"
-    "time"
+	"context"
+	"flag"
+	"github.com/0xJacky/Nginx-UI/server/model"
+	"github.com/0xJacky/Nginx-UI/server/router"
+	"github.com/0xJacky/Nginx-UI/server/settings"
+	"github.com/0xJacky/Nginx-UI/server/tool"
+	"github.com/gin-gonic/gin"
+	"log"
+	"mime"
+	"net/http"
+	"os/signal"
+	"syscall"
+	"time"
 )
 
 func main() {
-    // Create context that listens for the interrupt signal from the OS.
-    ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
-    defer stop()
+	// Create context that listens for the interrupt signal from the OS.
+	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
+	defer stop()
 
-    // Hack: fix wrong Content Type of .js file on some OS platforms
-    // See https://github.com/golang/go/issues/32350
-    _ = mime.AddExtensionType(".js", "text/javascript; charset=utf-8")
+	// Hack: fix wrong Content Type of .js file on some OS platforms
+	// See https://github.com/golang/go/issues/32350
+	_ = mime.AddExtensionType(".js", "text/javascript; charset=utf-8")
 
-    var confPath string
-    flag.StringVar(&confPath, "config", "app.ini", "Specify the configuration file")
-    flag.Parse()
+	var confPath string
+	flag.StringVar(&confPath, "config", "app.ini", "Specify the configuration file")
+	flag.Parse()
 
-    gin.SetMode(settings.ServerSettings.RunMode)
-    
-    settings.Init(confPath)
-    log.Printf("nginx config dir path: %s", tool2.GetNginxConfPath(""))
-    if "" != settings.ServerSettings.JwtSecret {
-        model.Init()
-        go tool2.AutoCert()
-    }
+	gin.SetMode(settings.ServerSettings.RunMode)
 
-    srv := &http.Server{
-        Addr:    ":" + settings.ServerSettings.HttpPort,
-        Handler: router.InitRouter(),
-    }
+	settings.Init(confPath)
+	log.Printf("nginx config dir path: %s", tool.GetNginxConfPath(""))
+	if "" != settings.ServerSettings.JwtSecret {
+		model.Init()
+		go tool.AutoCert()
+		go tool.RecordCpuUsage()
+	}
 
-    // Initializing the server in a goroutine so that
-    // it won't block the graceful shutdown handling below
-    go func() {
-        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
-            log.Fatalf("listen: %s\n", err)
-        }
-    }()
+	srv := &http.Server{
+		Addr:    ":" + settings.ServerSettings.HttpPort,
+		Handler: router.InitRouter(),
+	}
 
-    // Listen for the interrupt signal.
-    <-ctx.Done()
+	// Initializing the server in a goroutine so that
+	// it won't block the graceful shutdown handling below
+	go func() {
+		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+			log.Fatalf("listen: %s\n", err)
+		}
+	}()
 
-    // Restore default behavior on the interrupt signal and notify user of shutdown.
-    stop()
-    log.Println("shutting down gracefully, press Ctrl+C again to force")
+	// Listen for the interrupt signal.
+	<-ctx.Done()
 
-    // The context is used to inform the server it has 5 seconds to finish
-    // the request it is currently handling
-    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
-    defer cancel()
-    if err := srv.Shutdown(ctx); err != nil {
-        log.Fatal("Server forced to shutdown: ", err)
-    }
+	// Restore default behavior on the interrupt signal and notify user of shutdown.
+	stop()
+	log.Println("shutting down gracefully, press Ctrl+C again to force")
 
-    log.Println("Server exiting")
+	// The context is used to inform the server it has 5 seconds to finish
+	// the request it is currently handling
+	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+	defer cancel()
+	if err := srv.Shutdown(ctx); err != nil {
+		log.Fatal("Server forced to shutdown: ", err)
+	}
+
+	log.Println("Server exiting")
 
 }

+ 8 - 0
server/api/analytic.go

@@ -3,6 +3,7 @@ package api
 import (
 	"encoding/json"
 	"fmt"
+	"github.com/0xJacky/Nginx-UI/server/tool"
 	"github.com/shirou/gopsutil/v3/cpu"
 	"github.com/shirou/gopsutil/v3/disk"
 	"github.com/shirou/gopsutil/v3/host"
@@ -97,3 +98,10 @@ func Analytic(c *gin.Context) {
 		}
 	}
 }
+
+func GetCpuUsageRecord(c *gin.Context) {
+	c.JSON(http.StatusOK, gin.H{
+		"user":  tool.CpuUserBuffer,
+		"total": tool.CpuTotalBuffer,
+	})
+}

+ 1 - 0
server/router/routers.go

@@ -38,6 +38,7 @@ func InitRouter() *gin.Engine {
 		g := g.Group("/", authRequired())
 		{
 			g.GET("/analytic", api.Analytic)
+			g.GET("/analytic/cpu", api.GetCpuUsageRecord)
 
 			g.GET("/users", api.GetUsers)
 			g.GET("/user/:id", api.GetUser)

+ 45 - 0
server/tool/cpu_usage.go

@@ -0,0 +1,45 @@
+package tool
+
+import (
+	"github.com/shirou/gopsutil/v3/cpu"
+	"runtime"
+	"time"
+)
+
+type cpuUsage struct {
+	Time  time.Time `json:"x"`
+	Usage float64   `json:"y"`
+}
+
+var CpuUserBuffer []cpuUsage
+var CpuTotalBuffer []cpuUsage
+
+func RecordCpuUsage() {
+	for {
+		cpuTimesBefore, _ := cpu.Times(false)
+		time.Sleep(1000 * time.Millisecond)
+		cpuTimesAfter, _ := cpu.Times(false)
+		threadNum := runtime.GOMAXPROCS(0)
+
+		cpuUserUsage := (cpuTimesAfter[0].User - cpuTimesBefore[0].User) / (float64(1000*threadNum) / 1000)
+		cpuSystemUsage := (cpuTimesAfter[0].System - cpuTimesBefore[0].System) / (float64(1000*threadNum) / 1000)
+		now := time.Now()
+		u := cpuUsage{
+			Time:  now,
+			Usage: cpuUserUsage,
+		}
+		CpuUserBuffer = append(CpuUserBuffer, u)
+		s := cpuUsage{
+			Time:  now,
+			Usage: cpuUserUsage + cpuSystemUsage,
+		}
+		CpuTotalBuffer = append(CpuTotalBuffer, s)
+		if len(CpuUserBuffer) > 200 {
+			CpuUserBuffer = CpuUserBuffer[1:]
+		}
+		if len(CpuTotalBuffer) > 200 {
+			CpuTotalBuffer = CpuTotalBuffer[1:]
+		}
+		// time.Sleep(1 * time.Second)
+	}
+}