github.com/matrixorigin/matrixone@v0.7.0/pkg/util/metric/batch_collector.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 21 "github.com/matrixorigin/matrixone/pkg/logutil" 22 "github.com/matrixorigin/matrixone/pkg/util/trace" 23 prom "github.com/prometheus/client_golang/prometheus" 24 ) 25 26 type cacheKey = int 27 28 const ( 29 cacheKeyMemStats cacheKey = iota 30 cacheKeyProcess 31 cacheKeyDiskIO 32 cacheKeyNetIO 33 ) 34 35 type statCaches struct { 36 newest int 37 //TODO(aptend): use array 38 entries map[cacheKey]cacheEntry 39 } 40 41 type cacheEntry struct { 42 version int 43 value any 44 } 45 46 func (c *statCaches) invalidateAll() { 47 c.newest += 1 48 } 49 50 func (c *statCaches) get(key cacheKey) (any, bool) { 51 if entry, ok := c.entries[key]; !ok { 52 return nil, false 53 } else if entry.version != c.newest { 54 return nil, false 55 } else { 56 return entry.value, true 57 } 58 } 59 60 func (c *statCaches) put(key cacheKey, val any) { 61 c.entries[key] = cacheEntry{ 62 version: c.newest, 63 value: val, 64 } 65 } 66 67 func (c *statCaches) getOrInsert(key cacheKey, f func() any) any { 68 if val, ok := c.get(key); ok { 69 return val 70 } 71 toPut := f() 72 c.put(key, toPut) 73 return toPut 74 } 75 76 type simpleEntry interface { 77 Desc() *prom.Desc 78 // entry return the metric for now. it can fetch from the caches or just compute by itself 79 Metric(context.Context, *statCaches) (prom.Metric, error) 80 } 81 82 type batchStatsCollector struct { 83 selfAsPromCollector 84 entris []simpleEntry 85 caches *statCaches 86 collected bool 87 sync.Mutex 88 } 89 90 func newBatchStatsCollector(entries ...simpleEntry) Collector { 91 c := &batchStatsCollector{ 92 entris: entries, 93 caches: &statCaches{ 94 newest: 1, 95 entries: make(map[int]cacheEntry), 96 }, 97 } 98 c.init(c) 99 return c 100 } 101 102 // Describe returns all descriptions of the collector. 103 func (c *batchStatsCollector) Describe(ch chan<- *prom.Desc) { 104 for _, e := range c.entris { 105 ch <- e.Desc() 106 } 107 } 108 109 // Collect returns the current state of all metrics of the collector. 110 func (c *batchStatsCollector) Collect(ch chan<- prom.Metric) { 111 c.Lock() 112 defer c.Unlock() 113 ctx, span := trace.Start(context.Background(), "batchStatsCollector.Collect") 114 defer span.End() 115 c.caches.invalidateAll() 116 for _, e := range c.entris { 117 m, err := e.Metric(ctx, c.caches) 118 if err != nil { 119 if err.Error() == "not implemented yet" && c.collected { 120 // log not implemented once, otherwise it is too annoying 121 continue 122 } 123 logutil.Warnf("[Metric] %s collect a error: %v", e.Desc().String(), err) 124 } else { 125 // as we logged already, no need to issue a InvalidMetric 126 ch <- m 127 } 128 } 129 c.collected = true 130 }