github.com/netdata/go.d.plugin@v0.58.1/modules/cockroachdb/collect.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package cockroachdb
     4  
     5  import (
     6  	"errors"
     7  
     8  	"github.com/netdata/go.d.plugin/pkg/prometheus"
     9  	"github.com/netdata/go.d.plugin/pkg/stm"
    10  )
    11  
    12  func validCockroachDBMetrics(scraped prometheus.Series) bool {
    13  	return scraped.FindByName("sql_restart_savepoint_count_internal").Len() > 0
    14  }
    15  
    16  func (c *CockroachDB) collect() (map[string]int64, error) {
    17  	scraped, err := c.prom.ScrapeSeries()
    18  	if err != nil {
    19  		return nil, err
    20  	}
    21  
    22  	if !validCockroachDBMetrics(scraped) {
    23  		return nil, errors.New("returned metrics aren't CockroachDB metrics")
    24  	}
    25  
    26  	mx := collectScraped(scraped, metrics)
    27  	calcUsableCapacity(mx)
    28  	calcUnusableCapacity(mx)
    29  	calcTotalCapacityUsedPercentage(mx)
    30  	calcUsableCapacityUsedPercentage(mx)
    31  	calcRocksDBCacheHitRate(mx)
    32  	calcActiveReplicas(mx)
    33  	calcCPUUsagePercent(mx)
    34  
    35  	return stm.ToMap(mx), nil
    36  }
    37  
    38  const precision = 1000
    39  
    40  func collectScraped(scraped prometheus.Series, metricList []string) map[string]float64 {
    41  	mx := make(map[string]float64)
    42  	for _, name := range metricList {
    43  		if ms := scraped.FindByName(name); ms.Len() == 1 {
    44  			if isMetricFloat(name) {
    45  				mx[name] = ms.Max() * precision
    46  			} else {
    47  				mx[name] = ms.Max()
    48  			}
    49  		}
    50  	}
    51  	return mx
    52  }
    53  
    54  func calcUsableCapacity(mx map[string]float64) {
    55  	if !hasAll(mx, metricCapacityAvailable, metricCapacityUsed) {
    56  		return
    57  	}
    58  	available := mx[metricCapacityAvailable]
    59  	used := mx[metricCapacityUsed]
    60  
    61  	mx[metricCapacityUsable] = available + used
    62  }
    63  
    64  func calcUnusableCapacity(mx map[string]float64) {
    65  	if !hasAll(mx, metricCapacity, metricCapacityAvailable, metricCapacityUsed) {
    66  		return
    67  	}
    68  	total := mx[metricCapacity]
    69  	available := mx[metricCapacityAvailable]
    70  	used := mx[metricCapacityUsed]
    71  
    72  	mx[metricCapacityUnusable] = total - (available + used)
    73  }
    74  
    75  func calcTotalCapacityUsedPercentage(mx map[string]float64) {
    76  	if !hasAll(mx, metricCapacity, metricCapacityUnusable, metricCapacityUsed) {
    77  		return
    78  	}
    79  	total := mx[metricCapacity]
    80  	unusable := mx[metricCapacityUnusable]
    81  	used := mx[metricCapacityUsed]
    82  
    83  	if mx[metricCapacity] == 0 {
    84  		mx[metricCapacityUsedPercentage] = 0
    85  	} else {
    86  		mx[metricCapacityUsedPercentage] = (unusable + used) / total * 100 * precision
    87  	}
    88  }
    89  
    90  func calcUsableCapacityUsedPercentage(mx map[string]float64) {
    91  	if !hasAll(mx, metricCapacityUsable, metricCapacityUsed) {
    92  		return
    93  	}
    94  	usable := mx[metricCapacityUsable]
    95  	used := mx[metricCapacityUsed]
    96  
    97  	if usable == 0 {
    98  		mx[metricCapacityUsableUsedPercentage] = 0
    99  	} else {
   100  		mx[metricCapacityUsableUsedPercentage] = used / usable * 100 * precision
   101  	}
   102  }
   103  
   104  func calcRocksDBCacheHitRate(mx map[string]float64) {
   105  	if !hasAll(mx, metricRocksDBBlockCacheHits, metricRocksDBBlockCacheMisses) {
   106  		return
   107  	}
   108  	hits := mx[metricRocksDBBlockCacheHits]
   109  	misses := mx[metricRocksDBBlockCacheMisses]
   110  
   111  	if sum := hits + misses; sum == 0 {
   112  		mx[metricRocksDBBlockCacheHitRate] = 0
   113  	} else {
   114  		mx[metricRocksDBBlockCacheHitRate] = hits / sum * 100 * precision
   115  	}
   116  }
   117  
   118  func calcActiveReplicas(mx map[string]float64) {
   119  	if !hasAll(mx, metricReplicasQuiescent) {
   120  		return
   121  	}
   122  	total := mx[metricReplicas]
   123  	quiescent := mx[metricReplicasQuiescent]
   124  
   125  	mx[metricReplicasActive] = total - quiescent
   126  }
   127  
   128  func calcCPUUsagePercent(mx map[string]float64) {
   129  	if hasAll(mx, metricSysCPUUserPercent) {
   130  		mx[metricSysCPUUserPercent] *= 100
   131  	}
   132  	if hasAll(mx, metricSysCPUSysPercent) {
   133  		mx[metricSysCPUSysPercent] *= 100
   134  	}
   135  	if hasAll(mx, metricSysCPUCombinedPercentNormalized) {
   136  		mx[metricSysCPUCombinedPercentNormalized] *= 100
   137  	}
   138  }
   139  
   140  func isMetricFloat(name string) bool {
   141  	// only Float metrics (see NewGaugeFloat64 in the cockroach repo):
   142  	// - GcPausePercent, CPUUserPercent, CPUCombinedPercentNorm, AverageQueriesPerSecond, AverageWritesPerSecond
   143  	switch name {
   144  	case metricSysCPUUserPercent,
   145  		metricSysCPUSysPercent,
   146  		metricSysCPUCombinedPercentNormalized,
   147  		metricRebalancingQueriesPerSecond,
   148  		metricRebalancingWritesPerSecond:
   149  		return true
   150  	}
   151  	return false
   152  }
   153  
   154  func hasAll(mx map[string]float64, key string, rest ...string) bool {
   155  	_, ok := mx[key]
   156  	if len(rest) == 0 {
   157  		return ok
   158  	}
   159  	return ok && hasAll(mx, rest[0], rest[1:]...)
   160  }