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 }