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