github.com/matrixorigin/matrixone@v0.7.0/pkg/util/metric/metric_exporter.go (about) 1 // Copyright 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package metric 16 17 import ( 18 "context" 19 "sync" 20 "sync/atomic" 21 "time" 22 23 "github.com/matrixorigin/matrixone/pkg/logutil" 24 pb "github.com/matrixorigin/matrixone/pkg/pb/metric" 25 prom "github.com/prometheus/client_golang/prometheus" 26 ) 27 28 type MetricExporter interface { 29 // ExportMetricFamily can be used by a metric to push data. this method must be thread safe 30 ExportMetricFamily(context.Context, *pb.MetricFamily) error 31 Start(context.Context) bool 32 Stop(bool) (<-chan struct{}, bool) 33 } 34 35 type metricExporter struct { 36 localCollector MetricCollector 37 nodeUUID string 38 role string 39 gather prom.Gatherer 40 isRunning int32 41 cancel context.CancelFunc 42 stopWg sync.WaitGroup 43 sync.Mutex 44 histFamilies []*pb.MetricFamily 45 now func() int64 46 } 47 48 func newMetricExporter(gather prom.Gatherer, collector MetricCollector, node, role string) MetricExporter { 49 m := &metricExporter{ 50 localCollector: collector, 51 nodeUUID: node, 52 role: role, 53 gather: gather, 54 now: func() int64 { return time.Now().UnixMicro() }, 55 } 56 return m 57 } 58 59 func (e *metricExporter) ExportMetricFamily(ctx context.Context, mf *pb.MetricFamily) error { 60 // already batched RawHist metric will be send immediately 61 if isFullBatchRawHist(mf) { 62 mfs := []*pb.MetricFamily{mf} 63 mfs = e.prepareSend(mfs) 64 e.send(mfs) 65 } else { 66 e.Lock() 67 defer e.Unlock() 68 e.histFamilies = append(e.histFamilies, mf) 69 } 70 return nil 71 } 72 73 func (e *metricExporter) Stop(_ bool) (<-chan struct{}, bool) { 74 if atomic.SwapInt32(&e.isRunning, 0) == 0 { 75 return nil, false 76 } 77 e.cancel() 78 stopCh := make(chan struct{}) 79 go func() { e.stopWg.Wait(); close(stopCh) }() 80 return stopCh, true 81 } 82 83 func (e *metricExporter) Start(inputCtx context.Context) bool { 84 if atomic.SwapInt32(&e.isRunning, 1) == 1 { 85 return false 86 } 87 ctx, cancel := context.WithCancel(inputCtx) 88 e.cancel = cancel 89 e.stopWg.Add(1) 90 go func() { 91 defer e.stopWg.Done() 92 ticker := time.NewTicker(getGatherInterval()) 93 defer ticker.Stop() 94 for { 95 select { 96 case <-ticker.C: 97 e.gatherAndSend() 98 case <-ctx.Done(): 99 return 100 } 101 } 102 }() 103 return true 104 } 105 106 func (e *metricExporter) send(mfs []*pb.MetricFamily) { 107 if e.localCollector == nil { 108 panic("[Metric] Only a local MetricCollector") 109 } 110 err := e.localCollector.SendMetrics(context.TODO(), mfs) 111 if err != nil { 112 logutil.Errorf("[Metric] exporter send err: %v", err) 113 } 114 } 115 116 func (e *metricExporter) addCommonInfo(mfs []*pb.MetricFamily) { 117 now := e.now() 118 for _, mf := range mfs { 119 mf.Role = e.role 120 mf.Node = e.nodeUUID 121 for _, m := range mf.Metric { 122 m.Collecttime = now 123 } 124 } 125 } 126 127 func (e *metricExporter) prepareSend(mfs []*pb.MetricFamily) []*pb.MetricFamily { 128 e.Lock() 129 mfs = append(mfs, e.histFamilies...) 130 e.histFamilies = e.histFamilies[:0] 131 e.Unlock() 132 e.addCommonInfo(mfs) 133 return mfs 134 } 135 136 func (e *metricExporter) gatherAndSend() { 137 prommfs, err := e.gather.Gather() 138 if err != nil { 139 logutil.Errorf("[Metric] gather error: %v", err) 140 } 141 mfs := pb.P2MMetricFamilies(prommfs) 142 mfs = e.prepareSend(mfs) 143 e.send(mfs) 144 }