github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/catgo/cat-go/cat/aggregator_metric.go (about)

     1  package cat
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"time"
     7  
     8  	"github.com/artisanhe/tools/catgo/cat-go/message"
     9  )
    10  
    11  type metricData struct {
    12  	name     string
    13  	count    int
    14  	duration time.Duration
    15  }
    16  
    17  type metricAggregator struct {
    18  	scheduleMixin
    19  	ch      chan *metricData
    20  	dataMap map[string]*metricData
    21  	ticker  *time.Ticker
    22  }
    23  
    24  func (p *metricAggregator) GetName() string {
    25  	return "MetricAggregator"
    26  }
    27  
    28  func (p *metricAggregator) afterStart() {
    29  	p.ticker = time.NewTicker(metricAggregatorInterval)
    30  }
    31  
    32  func (p *metricAggregator) beforeStop() {
    33  	close(p.ch)
    34  
    35  	for event := range p.ch {
    36  		p.putOrMerge(event)
    37  	}
    38  	p.collectAndSend()
    39  
    40  	p.ticker.Stop()
    41  }
    42  
    43  func (p *metricAggregator) process() {
    44  	select {
    45  	case sig := <-p.signals:
    46  		p.handle(sig)
    47  	case data := <-p.ch:
    48  		p.putOrMerge(data)
    49  	case <-p.ticker.C:
    50  		p.collectAndSend()
    51  	}
    52  }
    53  
    54  func (p *metricAggregator) collectAndSend() {
    55  	dataMap := p.dataMap
    56  	p.dataMap = make(map[string]*metricData)
    57  	p.send(dataMap)
    58  }
    59  
    60  func (p *metricAggregator) send(dataMap map[string]*metricData) {
    61  	if len(dataMap) == 0 {
    62  		return
    63  	}
    64  
    65  	t := message.NewTransaction(typeSystem, nameMetricAggregator, aggregator.flush)
    66  	defer t.Complete()
    67  
    68  	for _, data := range dataMap {
    69  		metric := message.NewMetric("", data.name, nil)
    70  
    71  		if data.duration > 0 {
    72  			metric.SetStatus("S,C")
    73  			duration := data.duration.Nanoseconds() / time.Millisecond.Nanoseconds()
    74  			metric.SetData(fmt.Sprintf("%d,%d", data.count, duration))
    75  		} else {
    76  			metric.SetStatus("C")
    77  			metric.SetData(strconv.Itoa(data.count))
    78  		}
    79  
    80  		t.AddChild(metric)
    81  	}
    82  }
    83  
    84  func (p *metricAggregator) putOrMerge(data *metricData) {
    85  	if item, ok := p.dataMap[data.name]; ok {
    86  		item.count += data.count
    87  		item.duration += data.duration
    88  	} else {
    89  		p.dataMap[data.name] = data
    90  	}
    91  }
    92  
    93  func newMetricAggregator() *metricAggregator {
    94  	return &metricAggregator{
    95  		scheduleMixin: makeScheduleMixedIn(signalMetricAggregatorExit),
    96  		ch:            make(chan *metricData, metricAggregatorChannelCapacity),
    97  		dataMap:       make(map[string]*metricData),
    98  	}
    99  }
   100  
   101  func (p *metricAggregator) AddDuration(name string, duration time.Duration) {
   102  	select {
   103  	case p.ch <- &metricData{
   104  		name:     name,
   105  		count:    1,
   106  		duration: duration,
   107  	}:
   108  	default:
   109  		logger.Warning("Metric aggregator is full")
   110  	}
   111  }
   112  
   113  func (p *metricAggregator) AddCount(name string, count int) {
   114  	select {
   115  	case p.ch <- &metricData{
   116  		name:     name,
   117  		count:    count,
   118  		duration: 0,
   119  	}:
   120  	default:
   121  		logger.Warning("Metric aggregator is full")
   122  	}
   123  }