github.com/codingeasygo/util@v0.0.0-20231206062002-1ce2f004b7d9/monitor/monitor.go (about) 1 package monitor 2 3 import ( 4 "fmt" 5 "math" 6 "path/filepath" 7 "sort" 8 "strings" 9 "sync" 10 11 "github.com/codingeasygo/util/xmap" 12 "github.com/codingeasygo/util/xtime" 13 ) 14 15 type Statable interface { 16 State() (interface{}, error) 17 } 18 19 type State struct { 20 Name string `json:"name"` 21 Min int64 `json:"min"` 22 Max int64 `json:"max"` 23 Total int64 `json:"total"` 24 Count int64 `json:"count"` 25 ConcMax int64 `json:"con_max"` 26 ConcAvg int64 `json:"con_avg"` 27 // 28 concAll uint64 29 concCount uint64 30 } 31 32 type Monitor struct { 33 Used map[string]*State 34 Pending map[string]int64 35 max map[string]int64 36 lck sync.RWMutex 37 sequence uint64 38 } 39 40 func New() *Monitor { 41 return &Monitor{ 42 Used: map[string]*State{}, 43 Pending: map[string]int64{}, 44 max: map[string]int64{}, 45 lck: sync.RWMutex{}, 46 } 47 } 48 func (m *Monitor) Start(name string) string { 49 m.lck.Lock() 50 defer m.lck.Unlock() 51 m.sequence++ 52 var id = fmt.Sprintf("%v/%v", name, m.sequence) 53 m.Pending[id] = xtime.Now() 54 m.max[name]++ 55 old, ok := m.Used[name] 56 if !ok { 57 old = &State{Name: name, Min: math.MaxInt64} 58 } 59 old.concAll += uint64(m.max[name]) 60 old.concCount++ 61 old.ConcAvg = int64(old.concAll / old.concCount) 62 if old.ConcMax < m.max[name] { 63 old.ConcMax = m.max[name] 64 } 65 return id 66 } 67 68 func (m *Monitor) Start_(id string) { 69 m.lck.Lock() 70 defer m.lck.Unlock() 71 m.Pending[id] = xtime.Now() 72 } 73 74 func (m *Monitor) Done(id string) { 75 m.lck.Lock() 76 defer m.lck.Unlock() 77 beg, ok := m.Pending[id] 78 if !ok { 79 return 80 } 81 delete(m.Pending, id) 82 name := filepath.Dir(id) 83 name = strings.TrimSuffix(name, "/") 84 old, ok := m.Used[name] 85 if !ok { 86 old = &State{Name: name, Min: math.MaxInt64} 87 } 88 used := xtime.Now() - beg 89 old.Total += used 90 old.Count++ 91 if old.Max < used { 92 old.Max = used 93 } 94 if old.Min > used { 95 old.Min = used 96 } 97 m.Used[name] = old 98 m.max[name]-- 99 } 100 101 func (m *Monitor) State() (interface{}, error) { 102 m.lck.RLock() 103 defer m.lck.RUnlock() 104 var used = []xmap.M{} 105 for _, u := range m.Used { 106 used = append(used, xmap.M{ 107 "name": u.Name, 108 "min": u.Min, 109 "max": u.Max, 110 "total": u.Total, 111 "count": u.Count, 112 "avg": u.Total / u.Count, 113 "conc_max": u.ConcMax, 114 "conc_avg": u.ConcAvg, 115 }) 116 } 117 sort.Sort(xmap.NewMSorter(xmap.WrapArray(used), 0, true, "/avg")) 118 // 119 var pending = map[string]int64{} 120 for k, v := range m.Pending { 121 pending[k] = v 122 } 123 // 124 return xmap.M{ 125 "used": used, 126 "pending": pending, 127 }, nil 128 }