github.com/gofiber/fiber/v2@v2.47.0/middleware/monitor/monitor.go (about) 1 package monitor 2 3 import ( 4 "os" 5 "sync" 6 "sync/atomic" 7 "time" 8 9 "github.com/gofiber/fiber/v2" 10 "github.com/gofiber/fiber/v2/internal/gopsutil/cpu" 11 "github.com/gofiber/fiber/v2/internal/gopsutil/load" 12 "github.com/gofiber/fiber/v2/internal/gopsutil/mem" 13 "github.com/gofiber/fiber/v2/internal/gopsutil/net" 14 "github.com/gofiber/fiber/v2/internal/gopsutil/process" 15 ) 16 17 type stats struct { 18 PID statsPID `json:"pid"` 19 OS statsOS `json:"os"` 20 } 21 22 type statsPID struct { 23 CPU float64 `json:"cpu"` 24 RAM uint64 `json:"ram"` 25 Conns int `json:"conns"` 26 } 27 28 type statsOS struct { 29 CPU float64 `json:"cpu"` 30 RAM uint64 `json:"ram"` 31 TotalRAM uint64 `json:"total_ram"` 32 LoadAvg float64 `json:"load_avg"` 33 Conns int `json:"conns"` 34 } 35 36 var ( 37 monitPIDCPU atomic.Value 38 monitPIDRAM atomic.Value 39 monitPIDConns atomic.Value 40 41 monitOSCPU atomic.Value 42 monitOSRAM atomic.Value 43 monitOSTotalRAM atomic.Value 44 monitOSLoadAvg atomic.Value 45 monitOSConns atomic.Value 46 ) 47 48 var ( 49 mutex sync.RWMutex 50 once sync.Once 51 data = &stats{} 52 ) 53 54 // New creates a new middleware handler 55 func New(config ...Config) fiber.Handler { 56 // Set default config 57 cfg := configDefault(config...) 58 59 // Start routine to update statistics 60 once.Do(func() { 61 p, _ := process.NewProcess(int32(os.Getpid())) //nolint:errcheck // TODO: Handle error 62 63 updateStatistics(p) 64 65 go func() { 66 for { 67 time.Sleep(cfg.Refresh) 68 69 updateStatistics(p) 70 } 71 }() 72 }) 73 74 // Return new handler 75 //nolint:errcheck // Ignore the type-assertion errors 76 return func(c *fiber.Ctx) error { 77 // Don't execute middleware if Next returns true 78 if cfg.Next != nil && cfg.Next(c) { 79 return c.Next() 80 } 81 82 if c.Method() != fiber.MethodGet { 83 return fiber.ErrMethodNotAllowed 84 } 85 if c.Get(fiber.HeaderAccept) == fiber.MIMEApplicationJSON || cfg.APIOnly { 86 mutex.Lock() 87 data.PID.CPU, _ = monitPIDCPU.Load().(float64) 88 data.PID.RAM, _ = monitPIDRAM.Load().(uint64) 89 data.PID.Conns, _ = monitPIDConns.Load().(int) 90 91 data.OS.CPU, _ = monitOSCPU.Load().(float64) 92 data.OS.RAM, _ = monitOSRAM.Load().(uint64) 93 data.OS.TotalRAM, _ = monitOSTotalRAM.Load().(uint64) 94 data.OS.LoadAvg, _ = monitOSLoadAvg.Load().(float64) 95 data.OS.Conns, _ = monitOSConns.Load().(int) 96 mutex.Unlock() 97 return c.Status(fiber.StatusOK).JSON(data) 98 } 99 c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8) 100 return c.Status(fiber.StatusOK).SendString(cfg.index) 101 } 102 } 103 104 func updateStatistics(p *process.Process) { 105 pidCPU, err := p.CPUPercent() 106 if err == nil { 107 monitPIDCPU.Store(pidCPU / 10) 108 } 109 110 if osCPU, err := cpu.Percent(0, false); err == nil && len(osCPU) > 0 { 111 monitOSCPU.Store(osCPU[0]) 112 } 113 114 if pidRAM, err := p.MemoryInfo(); err == nil && pidRAM != nil { 115 monitPIDRAM.Store(pidRAM.RSS) 116 } 117 118 if osRAM, err := mem.VirtualMemory(); err == nil && osRAM != nil { 119 monitOSRAM.Store(osRAM.Used) 120 monitOSTotalRAM.Store(osRAM.Total) 121 } 122 123 if loadAvg, err := load.Avg(); err == nil && loadAvg != nil { 124 monitOSLoadAvg.Store(loadAvg.Load1) 125 } 126 127 pidConns, err := net.ConnectionsPid("tcp", p.Pid) 128 if err == nil { 129 monitPIDConns.Store(len(pidConns)) 130 } 131 132 osConns, err := net.Connections("tcp") 133 if err == nil { 134 monitOSConns.Store(len(osConns)) 135 } 136 }