trpc.group/trpc-go/trpc-go@v1.0.3/metrics/sink_console.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package metrics 15 16 import ( 17 "encoding/json" 18 "fmt" 19 "sort" 20 "sync" 21 "time" 22 ) 23 24 // NewConsoleSink creates a new console sink. 25 func NewConsoleSink() Sink { 26 return &ConsoleSink{ 27 counters: make(map[string]float64), 28 gauges: make(map[string]float64), 29 timers: make(map[string]timer), 30 histograms: make(map[string]histogram), 31 } 32 } 33 34 // ConsoleSink defines the console sink. 35 type ConsoleSink struct { 36 countersMu sync.RWMutex 37 counters map[string]float64 38 39 gaugesMu sync.RWMutex 40 gauges map[string]float64 41 42 timersMu sync.RWMutex 43 timers map[string]timer 44 45 histogramsMu sync.RWMutex 46 histograms map[string]histogram 47 } 48 49 // Name returns console sink name. 50 func (c *ConsoleSink) Name() string { 51 return "console" 52 } 53 54 // Report reports a record. 55 func (c *ConsoleSink) Report(rec Record, opts ...Option) error { 56 if len(rec.dimensions) <= 0 { 57 return c.reportSingleDimensionMetrics(rec, opts...) 58 } 59 return c.reportMultiDimensionMetrics(rec, opts...) 60 } 61 62 func (c *ConsoleSink) reportSingleDimensionMetrics(rec Record, _ ...Option) error { 63 // almost all monitor systems support cumulant and instant. 64 for _, m := range rec.metrics { 65 switch m.policy { 66 case PolicySUM: 67 c.incrCounter(m.name, m.value) 68 case PolicySET: 69 c.setGauge(m.name, m.value) 70 case PolicyTimer: 71 c.recordTimer(m.name, time.Duration(m.value)) 72 case PolicyHistogram: 73 c.addSample(m.name, m.value) 74 default: 75 // not supported policies 76 } 77 } 78 return nil 79 } 80 81 func (c *ConsoleSink) reportMultiDimensionMetrics(rec Record, opts ...Option) error { 82 options := Options{} 83 for _, o := range opts { 84 o(&options) 85 } 86 87 type metric struct { 88 Name string `json:"name"` 89 Value float64 `json:"value"` 90 Policy Policy `json:"policy"` 91 } 92 metrics := make([]*metric, 0, len(rec.GetMetrics())) 93 for _, m := range rec.GetMetrics() { 94 metrics = append(metrics, &metric{Name: m.Name(), Value: m.Value(), Policy: m.Policy()}) 95 } 96 97 buf, err := json.Marshal(struct { 98 Name string `json:"name"` 99 Dimensions []*Dimension `json:"dimensions"` 100 Metrics []*metric `json:"metrics"` 101 }{ 102 Name: rec.GetName(), 103 Dimensions: rec.GetDimensions(), 104 Metrics: metrics, 105 }) 106 if err != nil { 107 return err 108 } 109 110 // a common multiple dimension report. 111 fmt.Printf("metrics multi-dimension = %s\n", string(buf)) 112 return nil 113 } 114 115 // incrCounter increases counter. 116 func (c *ConsoleSink) incrCounter(key string, value float64) { 117 if c.counters == nil { 118 return 119 } 120 c.countersMu.Lock() 121 c.counters[key] += value 122 c.countersMu.Unlock() 123 fmt.Printf("metrics counter[key] = %s val = %v\n", key, value) 124 } 125 126 // setGauge sets gauge. 127 func (c *ConsoleSink) setGauge(key string, value float64) { 128 if c.gauges == nil { 129 return 130 } 131 c.countersMu.Lock() 132 c.gauges[key] = value 133 c.countersMu.Unlock() 134 fmt.Printf("metrics gauge[key] = %s val = %v\n", key, value) 135 } 136 137 // recordTimer records timer. 138 func (c *ConsoleSink) recordTimer(key string, duration time.Duration) { 139 fmt.Printf("metrics timer[key] = %s val = %v\n", key, duration) 140 } 141 142 // addSample adds a sample. 143 func (c *ConsoleSink) addSample(key string, value float64) { 144 histogramsMutex.RLock() 145 h := histograms[key] 146 histogramsMutex.RUnlock() 147 148 v, ok := h.(*histogram) 149 if !ok { 150 return 151 } 152 hist := *v 153 154 histogramsMutex.Lock() 155 idx := sort.SearchFloat64s(hist.LookupByValue, value) 156 upperBound := hist.Buckets[idx].ValueUpperBound 157 hist.Buckets[idx].samples += value 158 histogramsMutex.Unlock() 159 160 fmt.Printf("metrics histogram[%s.%v] = %v\n", hist.Name, upperBound, hist.Buckets[idx].samples) 161 }