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

     1  package cat
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/artisanhe/tools/catgo/cat-go/message"
     9  )
    10  
    11  type transactionData struct {
    12  	mtype, name string
    13  
    14  	count, fail int
    15  
    16  	sum int64
    17  
    18  	durations map[int]int
    19  }
    20  
    21  //noinspection GoUnhandledErrorResult
    22  func encodeTransactionData(data *transactionData) *bytes.Buffer {
    23  	buf := newBuf()
    24  
    25  	buf.WriteRune(batchFlag)
    26  	buf.WriteInt(data.count)
    27  	buf.WriteRune(batchSplit)
    28  	buf.WriteInt(data.fail)
    29  	buf.WriteRune(batchSplit)
    30  	buf.WriteUInt64(uint64(data.sum))
    31  	buf.WriteRune(batchSplit)
    32  
    33  	i := 0
    34  	for k, v := range data.durations {
    35  		if i > 0 {
    36  			buf.WriteRune('|')
    37  		}
    38  		buf.WriteInt(k)
    39  		buf.WriteRune(',')
    40  		buf.WriteInt(v)
    41  		i++
    42  	}
    43  	buf.WriteRune(batchSplit)
    44  
    45  	return &buf.Buffer
    46  }
    47  
    48  func (p *transactionAggregator) GetName() string {
    49  	return "TransactionAggregator"
    50  }
    51  
    52  type transactionAggregator struct {
    53  	scheduleMixin
    54  	ch      chan *message.Transaction
    55  	dataMap map[string]*transactionData
    56  	ticker  *time.Ticker
    57  }
    58  
    59  func (p *transactionAggregator) collectAndSend() {
    60  	dataMap := p.dataMap
    61  	p.dataMap = make(map[string]*transactionData)
    62  	p.send(dataMap)
    63  }
    64  
    65  func (p *transactionAggregator) send(dataMap map[string]*transactionData) {
    66  	if len(dataMap) == 0 {
    67  		return
    68  	}
    69  	t := message.NewTransaction(typeSystem, nameTransactionAggregator, aggregator.flush)
    70  	defer t.Complete()
    71  
    72  	for _, data := range dataMap {
    73  		trans := message.NewTransaction(data.mtype, data.name, nil)
    74  		trans.SetData(encodeTransactionData(data).String())
    75  		trans.Complete()
    76  		t.AddChild(trans)
    77  	}
    78  }
    79  
    80  func (p *transactionAggregator) getOrDefault(transaction *message.Transaction) *transactionData {
    81  	key := fmt.Sprintf("%s,%s", transaction.Type, transaction.Name)
    82  
    83  	if data, ok := p.dataMap[key]; ok {
    84  		return data
    85  	} else {
    86  		p.dataMap[key] = &transactionData{
    87  			mtype:     transaction.GetType(),
    88  			name:      transaction.GetName(),
    89  			count:     0,
    90  			fail:      0,
    91  			sum:       0,
    92  			durations: make(map[int]int),
    93  		}
    94  		return p.dataMap[key]
    95  	}
    96  }
    97  
    98  func (p *transactionAggregator) afterStart() {
    99  	p.ticker = time.NewTicker(transactionAggregatorInterval)
   100  }
   101  
   102  func (p *transactionAggregator) beforeStop() {
   103  	close(p.ch)
   104  
   105  	for t := range p.ch {
   106  		p.getOrDefault(t).add(t)
   107  	}
   108  	p.collectAndSend()
   109  
   110  	p.ticker.Stop()
   111  }
   112  
   113  func (p *transactionAggregator) process() {
   114  	select {
   115  	case sig := <-p.signals:
   116  		p.handle(sig)
   117  	case t := <-p.ch:
   118  		p.getOrDefault(t).add(t)
   119  	case <-p.ticker.C:
   120  		p.collectAndSend()
   121  	}
   122  }
   123  
   124  func (p *transactionAggregator) Put(t *message.Transaction) {
   125  	if !IsEnabled() {
   126  		return
   127  	}
   128  
   129  	select {
   130  	case p.ch <- t:
   131  	default:
   132  		logger.Warning("Transaction aggregator is full")
   133  	}
   134  }
   135  
   136  func (data *transactionData) add(transaction *message.Transaction) {
   137  	data.count++
   138  
   139  	if transaction.GetStatus() != SUCCESS {
   140  		data.fail++
   141  	}
   142  
   143  	millis := duration2Millis(transaction.GetDuration())
   144  	data.sum += millis
   145  
   146  	duration := computeDuration(int(millis))
   147  	if _, ok := data.durations[duration]; ok {
   148  		data.durations[duration]++
   149  	} else {
   150  		data.durations[duration] = 1
   151  	}
   152  }
   153  
   154  func newTransactionAggregator() *transactionAggregator {
   155  	return &transactionAggregator{
   156  		scheduleMixin: makeScheduleMixedIn(signalTransactionAggregatorExit),
   157  		ch:            make(chan *message.Transaction, transactionAggregatorChannelCapacity),
   158  		dataMap:       make(map[string]*transactionData),
   159  	}
   160  }