github.com/netdata/go.d.plugin@v0.58.1/modules/couchbase/collect.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package couchbase 4 5 import ( 6 "encoding/json" 7 "fmt" 8 "io" 9 "net/http" 10 "net/url" 11 12 "github.com/netdata/go.d.plugin/agent/module" 13 "github.com/netdata/go.d.plugin/pkg/web" 14 ) 15 16 const ( 17 urlPathBucketsStats = "/pools/default/buckets" 18 19 precision = 1000 20 ) 21 22 func (cb *Couchbase) collect() (map[string]int64, error) { 23 ms, err := cb.scrapeCouchbase() 24 if err != nil { 25 return nil, fmt.Errorf("error on scraping couchbase: %v", err) 26 } 27 if ms.empty() { 28 return nil, nil 29 } 30 31 collected := make(map[string]int64) 32 cb.collectBasicStats(collected, ms) 33 34 return collected, nil 35 } 36 37 func (cb *Couchbase) collectBasicStats(collected map[string]int64, ms *cbMetrics) { 38 for _, b := range ms.BucketsBasicStats { 39 40 if !cb.collectedBuckets[b.Name] { 41 cb.collectedBuckets[b.Name] = true 42 cb.addBucketToCharts(b.Name) 43 } 44 45 bs := b.BasicStats 46 collected[indexDimID(b.Name, "quota_percent_used")] = int64(bs.QuotaPercentUsed * precision) 47 collected[indexDimID(b.Name, "ops_per_sec")] = int64(bs.OpsPerSec * precision) 48 collected[indexDimID(b.Name, "disk_fetches")] = int64(bs.DiskFetches) 49 collected[indexDimID(b.Name, "item_count")] = int64(bs.ItemCount) 50 collected[indexDimID(b.Name, "disk_used")] = int64(bs.DiskUsed) 51 collected[indexDimID(b.Name, "data_used")] = int64(bs.DataUsed) 52 collected[indexDimID(b.Name, "mem_used")] = int64(bs.MemUsed) 53 collected[indexDimID(b.Name, "vb_active_num_non_resident")] = int64(bs.VbActiveNumNonResident) 54 } 55 } 56 57 func (cb *Couchbase) addBucketToCharts(bucket string) { 58 cb.addDimToChart(bucketQuotaPercentUsedChart.ID, &module.Dim{ 59 ID: indexDimID(bucket, "quota_percent_used"), 60 Name: bucket, 61 Div: precision, 62 }) 63 64 cb.addDimToChart(bucketOpsPerSecChart.ID, &module.Dim{ 65 ID: indexDimID(bucket, "ops_per_sec"), 66 Name: bucket, 67 Div: precision, 68 }) 69 70 cb.addDimToChart(bucketDiskFetchesChart.ID, &module.Dim{ 71 ID: indexDimID(bucket, "disk_fetches"), 72 Name: bucket, 73 }) 74 75 cb.addDimToChart(bucketItemCountChart.ID, &module.Dim{ 76 ID: indexDimID(bucket, "item_count"), 77 Name: bucket, 78 }) 79 80 cb.addDimToChart(bucketDiskUsedChart.ID, &module.Dim{ 81 ID: indexDimID(bucket, "disk_used"), 82 Name: bucket, 83 }) 84 85 cb.addDimToChart(bucketDataUsedChart.ID, &module.Dim{ 86 ID: indexDimID(bucket, "data_used"), 87 Name: bucket, 88 }) 89 90 cb.addDimToChart(bucketMemUsedChart.ID, &module.Dim{ 91 ID: indexDimID(bucket, "mem_used"), 92 Name: bucket, 93 }) 94 95 cb.addDimToChart(bucketVBActiveNumNonResidentChart.ID, &module.Dim{ 96 ID: indexDimID(bucket, "vb_active_num_non_resident"), 97 Name: bucket, 98 }) 99 } 100 101 func (cb *Couchbase) addDimToChart(chartID string, dim *module.Dim) { 102 chart := cb.Charts().Get(chartID) 103 if chart == nil { 104 cb.Warningf("error on adding '%s' dimension: can not find '%s' chart", dim.ID, chartID) 105 return 106 } 107 if err := chart.AddDim(dim); err != nil { 108 cb.Warning(err) 109 return 110 } 111 chart.MarkNotCreated() 112 } 113 114 func (cb *Couchbase) scrapeCouchbase() (*cbMetrics, error) { 115 ms := &cbMetrics{} 116 req, _ := web.NewHTTPRequest(cb.Request) 117 req.URL.Path = urlPathBucketsStats 118 req.URL.RawQuery = url.Values{"skipMap": []string{"true"}}.Encode() 119 120 if err := cb.doOKDecode(req, &ms.BucketsBasicStats); err != nil { 121 return nil, err 122 } 123 return ms, nil 124 } 125 126 func (cb *Couchbase) doOKDecode(req *http.Request, in interface{}) error { 127 resp, err := cb.httpClient.Do(req) 128 if err != nil { 129 return fmt.Errorf("error on HTTP request '%s': %v", req.URL, err) 130 } 131 defer closeBody(resp) 132 133 if resp.StatusCode != http.StatusOK { 134 return fmt.Errorf("'%s' returned HTTP status code: %d", req.URL, resp.StatusCode) 135 } 136 137 if err := json.NewDecoder(resp.Body).Decode(in); err != nil { 138 return fmt.Errorf("error on decoding response from '%s': %v", req.URL, err) 139 } 140 return nil 141 } 142 143 func closeBody(resp *http.Response) { 144 if resp != nil && resp.Body != nil { 145 _, _ = io.Copy(io.Discard, resp.Body) 146 _ = resp.Body.Close() 147 } 148 } 149 150 func indexDimID(name, metric string) string { 151 return fmt.Sprintf("bucket_%s_%s", name, metric) 152 }