Files
plugin-summary/summary.go
2022-02-17 01:14:40 +08:00

192 lines
4.2 KiB
Go

package plugin_summary
import (
"github.com/gogf/gf/text/gregex"
"log"
"net/http"
"strings"
"time"
. "github.com/Monibuca/engine/v3"
. "github.com/Monibuca/utils/v3"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/net"
)
// Summary 系统摘要数据
var Summary ServerSummary
var config = struct {
SampleRate int
NetAdapter string //在容器化设备会有很多无效的虚拟网卡,只读取有意义的网卡
}{1, ""}
func init() {
plugin := PluginConfig{
Name: "Summary",
Config: &config,
HotConfig: map[string]func(interface{}){
"NetAdapter": func(v interface{}) {
config.NetAdapter = v.(string)
},
},
}
plugin.Install(Summary.StartSummary)
http.HandleFunc("/api/summary", summary)
}
func summary(w http.ResponseWriter, r *http.Request) {
CORS(w, r)
sse := NewSSE(w, r.Context())
Summary.Add()
defer Summary.Done()
sse.WriteJSON(&Summary)
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if err := sse.WriteJSON(&Summary); err != nil {
log.Println(err)
return
}
case <-r.Context().Done():
return
}
}
}
// ServerSummary 系统摘要定义
type ServerSummary struct {
Address string
Memory struct {
Total uint64
Free uint64
Used uint64
Usage float64
}
CPUUsage float64
HardDisk struct {
Total uint64
Free uint64
Used uint64
Usage float64
}
NetWork []NetWorkInfo
Streams []*Stream
lastNetWork []net.IOCountersStat
ref int
control chan bool
reportChan chan *ServerSummary
Children map[string]*ServerSummary
}
// NetWorkInfo 网速信息
type NetWorkInfo struct {
Name string
Receive uint64
Sent uint64
ReceiveSpeed uint64
SentSpeed uint64
}
//StartSummary 开始定时采集数据,每秒一次
func (s *ServerSummary) StartSummary() {
ticker := time.NewTicker(time.Second * time.Duration(config.SampleRate))
s.control = make(chan bool)
s.reportChan = make(chan *ServerSummary)
for {
select {
case <-ticker.C:
if s.ref > 0 {
Summary.collect()
}
case v := <-s.control:
if v {
if s.ref++; s.ref == 1 {
log.Println("start report summary")
TriggerHook("Summary", true)
}
} else {
if s.ref--; s.ref == 0 {
s.lastNetWork = nil
log.Println("stop report summary")
TriggerHook("Summary", false)
}
}
case report := <-s.reportChan:
s.Children[report.Address] = report
}
}
}
// Running 是否正在采集数据
func (s *ServerSummary) Running() bool {
return s.ref > 0
}
// Add 增加订阅者
func (s *ServerSummary) Add() {
s.control <- true
}
// Done 删除订阅者
func (s *ServerSummary) Done() {
s.control <- false
}
// Report 上报数据
func (s *ServerSummary) Report(slave *ServerSummary) {
s.reportChan <- slave
}
func (s *ServerSummary) collect() {
v, _ := mem.VirtualMemory()
d, _ := disk.Usage("/")
nv, _ := net.IOCounters(true)
s.Memory.Total = v.Total / 1024 / 1024
s.Memory.Free = v.Available / 1024 / 1024
s.Memory.Used = v.Used / 1024 / 1024
s.Memory.Usage = v.UsedPercent
if cc, _ := cpu.Percent(time.Second, false); len(cc) > 0 {
s.CPUUsage = cc[0]
}
s.HardDisk.Free = d.Free / 1024 / 1024 / 1024
s.HardDisk.Total = d.Total / 1024 / 1024 / 1024
s.HardDisk.Used = d.Used / 1024 / 1024 / 1024
s.HardDisk.Usage = d.UsedPercent
s.NetWork = make([]NetWorkInfo, 0)
for i, n := range nv {
if n.BytesRecv == 0 || !isNetAdapter(n.Name) {
continue
}
info := NetWorkInfo{}
info.Name = n.Name
info.Receive = n.BytesRecv
info.Sent = n.BytesSent
if s.lastNetWork != nil && len(s.lastNetWork) > i {
info.ReceiveSpeed = n.BytesRecv - s.lastNetWork[i].BytesRecv
info.SentSpeed = n.BytesSent - s.lastNetWork[i].BytesSent
}
s.NetWork = append(s.NetWork, info)
}
s.lastNetWork = nv
s.Streams = Streams.ToList()
return
}
//NetAdapter 通过匹配和正则判断要过滤的无效网卡
func isNetAdapter(name string) bool {
if name == "" {
return true
}
//正则用@作正则修饰符
if !strings.Contains(config.NetAdapter, "@") {
return strings.Contains(name, config.NetAdapter)
}
return gregex.IsMatchString(strings.Trim(config.NetAdapter, "@"), name)
}