diff --git a/frontend/src/api/analytic.js b/frontend/src/api/analytic.js
new file mode 100644
index 00000000..629641e2
--- /dev/null
+++ b/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
diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js
index 092cd39b..eced5e37 100644
--- a/frontend/src/api/index.js
+++ b/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
}
diff --git a/frontend/src/views/dashboard/DashBoard.vue b/frontend/src/views/dashboard/DashBoard.vue
index 8fe9424a..991bf9d9 100644
--- a/frontend/src/views/dashboard/DashBoard.vue
+++ b/frontend/src/views/dashboard/DashBoard.vue
@@ -10,10 +10,16 @@
%
-
Uptime {{ uptime }}
- Load Averages: 1min:{{ loadavg?.load1?.toFixed(2) }} |
+
+ Uptime
+ {{ uptime }}
+
+
+ Load Averages:
+ 1min:{{ loadavg?.load1?.toFixed(2) }} |
5min:{{ loadavg?.load5?.toFixed(2) }} |
- 15min:{{ loadavg?.load15?.toFixed(2) }}
+ 15min:{{ loadavg?.load15?.toFixed(2) }}
+
@@ -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()
diff --git a/main.go b/main.go
index ae820fc9..bb383e59 100644
--- a/main.go
+++ b/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")
}
diff --git a/server/api/analytic.go b/server/api/analytic.go
index 2ca3a54f..f5e45a85 100644
--- a/server/api/analytic.go
+++ b/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,
+ })
+}
diff --git a/server/router/routers.go b/server/router/routers.go
index 7f2885f3..c3fd2791 100644
--- a/server/router/routers.go
+++ b/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)
diff --git a/server/tool/cpu_usage.go b/server/tool/cpu_usage.go
new file mode 100644
index 00000000..8961e97a
--- /dev/null
+++ b/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)
+ }
+}