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  }