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  }