github.com/aergoio/aergo@v1.3.1/p2p/metric/metricsman.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package metric 7 8 import ( 9 "bytes" 10 "fmt" 11 "github.com/aergoio/aergo-lib/log" 12 "github.com/aergoio/aergo/p2p/p2putil" 13 "github.com/aergoio/aergo/types" 14 "sync" 15 "sync/atomic" 16 "time" 17 ) 18 19 type MetricsManager interface { 20 Start() 21 Stop() 22 23 NewMetric(pid types.PeerID, manNum uint32) *PeerMetric 24 Remove(pid types.PeerID, manNum uint32) *PeerMetric 25 26 Metric(pid types.PeerID) (*PeerMetric, bool) 27 Metrics() []*PeerMetric 28 29 Summary() map[string]interface{} 30 PrintMetrics() string 31 } 32 //go:generate mockgen -source=metricsman.go -package=p2pmock -destination=../p2pmock/mock_metricsman.go 33 34 type metricsManager struct { 35 logger *log.Logger 36 startTime time.Time 37 38 metricsMap map[types.PeerID]*PeerMetric 39 40 interval int 41 ticker *time.Ticker 42 mutex sync.RWMutex 43 44 deadTotalIn int64 45 deadTotalOut int64 46 } 47 48 var _ MetricsManager = (*metricsManager)(nil) 49 50 func NewMetricManager(interval int) *metricsManager { 51 mm := &metricsManager{logger: log.NewLogger("p2p"), metricsMap: make(map[types.PeerID]*PeerMetric), interval: interval, startTime: time.Now()} 52 53 return mm 54 } 55 56 func (mm *metricsManager) Start() { 57 go func() { 58 mm.logger.Info().Msg("Starting p2p metrics manager ") 59 mm.ticker = time.NewTicker(time.Second * time.Duration(mm.interval)) 60 for range mm.ticker.C { 61 mm.mutex.RLock() 62 //mm.logger.Debug().Int("peer_cnt", len(mm.metricsMap)).Msg("Calculating peer metrics") 63 for _, peerMetric := range mm.metricsMap { 64 peerMetric.InMetric.Calculate() 65 peerMetric.OutMetric.Calculate() 66 } 67 mm.mutex.RUnlock() 68 } 69 }() 70 } 71 72 func (mm *metricsManager) Stop() { 73 mm.logger.Info().Msg("Finishing p2p metrics manager") 74 mm.ticker.Stop() 75 } 76 77 func (mm *metricsManager) NewMetric(pid types.PeerID, manNum uint32) *PeerMetric { 78 mm.mutex.Lock() 79 defer mm.mutex.Unlock() 80 if old, found := mm.metricsMap[pid]; found { 81 mm.logger.Warn().Str("peer_id", p2putil.ShortForm(pid)).Uint32("oldNum", old.seq).Uint32("newNum",manNum).Msg("metric for to add peer is already exist. replacing new metric") 82 } 83 peerMetric := &PeerMetric{mm: mm, PeerID: pid, seq: manNum, InMetric:NewExponentMetric5(mm.interval), OutMetric:NewExponentMetric5(mm.interval), Since:time.Now()} 84 mm.metricsMap[pid] = peerMetric 85 return peerMetric 86 } 87 88 func (mm *metricsManager) Remove(pid types.PeerID, manNum uint32) *PeerMetric { 89 mm.mutex.Lock() 90 defer mm.mutex.Unlock() 91 if metric, found := mm.metricsMap[pid]; !found { 92 mm.logger.Warn().Str(p2putil.LogPeerID, p2putil.ShortForm(pid)).Msg("metric for to remove peer is not exist.") 93 return nil 94 } else { 95 if metric.seq != manNum { 96 mm.logger.Warn().Uint32("exist_num", metric.seq).Uint32("man_num", manNum).Str(p2putil.LogPeerID, p2putil.ShortForm(pid)).Msg("ignore remove. different manage number") 97 } 98 atomic.AddInt64(&mm.deadTotalIn, metric.totalIn) 99 atomic.AddInt64(&mm.deadTotalOut, metric.totalOut) 100 delete(mm.metricsMap, pid) 101 return metric 102 } 103 } 104 105 func (mm *metricsManager) Metric(pid types.PeerID) (*PeerMetric, bool) { 106 mm.mutex.RLock() 107 defer mm.mutex.RUnlock() 108 109 pm, found := mm.metricsMap[pid] 110 return pm, found 111 } 112 113 func (mm *metricsManager) Metrics() []*PeerMetric { 114 mm.mutex.RLock() 115 defer mm.mutex.RUnlock() 116 view := make([]*PeerMetric, 0, len(mm.metricsMap)) 117 for _, pm := range mm.metricsMap { 118 view = append(view, pm) 119 } 120 return view 121 } 122 123 func (mm *metricsManager) Summary() map[string]interface{} { 124 // There can be a little error 125 sum := make(map[string]interface{}) 126 sum["since"] = mm.startTime 127 var totalIn, totalOut int64 128 if len(mm.Metrics()) > 0 { 129 var cnt = 0 130 //var inAps, inLoad, outAps, outLoad int64 131 for _, met := range mm.Metrics() { 132 cnt++ 133 totalIn += met.totalIn 134 totalOut += met.totalOut 135 } 136 } 137 totalIn += atomic.LoadInt64(&mm.deadTotalIn) 138 totalOut += atomic.LoadInt64(&mm.deadTotalOut) 139 sum["in"] = totalIn 140 sum["out"] = totalOut 141 return sum 142 } 143 144 func (mm *metricsManager) PrintMetrics() string { 145 sb := bytes.Buffer{} 146 sb.WriteString("p2p metric summary \n") 147 if len(mm.Metrics()) > 0 { 148 sb.WriteString("PeerID : IN_TOTAL, IN_AVR, IN_LOAD : OUT_TOTAL, OUT_AVR, OUT_LOAD\n") 149 for _, met := range mm.Metrics() { 150 sb.WriteString(p2putil.ShortForm(met.PeerID)) 151 sb.WriteString(fmt.Sprintf(" : %10d,%10d,%10d", met.totalIn, met.InMetric.APS(), met.InMetric.LoadScore())) 152 sb.WriteString(fmt.Sprintf(" : %10d,%10d,%10d", met.totalOut, met.OutMetric.APS(), met.OutMetric.LoadScore())) 153 sb.WriteString("\n") 154 } 155 } 156 return sb.String() 157 }