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  }