feat: allow collecting node-level metrics for Couchbase buckets (#9717)

This commit is contained in:
Alexander Krantz 2022-06-27 12:03:55 -07:00 committed by GitHub
parent 6b009f3072
commit fcc9373eba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 108 additions and 32 deletions

View File

@ -30,6 +30,14 @@ couchbase server.
## Use TLS but skip chain & host verification (defaults to false)
## If set to false, tls_cert and tls_key are required
# insecure_skip_verify = false
## Whether to collect cluster-wide bucket statistics
## It is recommended to disable this in favor of node_stats
## to get a better view of the cluster.
cluster_bucket_stats = true
## Whether to collect bucket stats for each individual node
node_bucket_stats = false
```
## Metrics
@ -46,12 +54,13 @@ Fields:
- memory_free (unit: bytes, example: 23181365248.0)
- memory_total (unit: bytes, example: 64424656896.0)
### couchbase_bucket
### couchbase_bucket and couchbase_node_bucket
Tags:
- cluster: whatever you called it in `servers` in the configuration, e.g.: `http://couchbase-0.example.com/`)
- bucket: the name of the couchbase bucket, e.g., `blastro-df`
- hostname: the hostname of the node the bucket metrics were collected from, e.g., `172.16.10.187:8091` (only present in `couchbase_node_bucket`)
Default bucket fields:

View File

@ -26,6 +26,9 @@ type Couchbase struct {
BucketStatsIncluded []string `toml:"bucket_stats_included"`
ClusterBucketStats bool `toml:"cluster_bucket_stats"`
NodeBucketStats bool `toml:"node_bucket_stats"`
bucketInclude filter.Filter
client *http.Client
@ -85,32 +88,55 @@ func (cb *Couchbase) gatherServer(acc telegraf.Accumulator, addr string) error {
acc.AddFields("couchbase_node", fields, tags)
}
for bucketName := range pool.BucketMap {
tags := map[string]string{"cluster": escapedAddr, "bucket": bucketName}
bs := pool.BucketMap[bucketName].BasicStats
fields := make(map[string]interface{})
cb.addBucketField(fields, "quota_percent_used", bs["quotaPercentUsed"])
cb.addBucketField(fields, "ops_per_sec", bs["opsPerSec"])
cb.addBucketField(fields, "disk_fetches", bs["diskFetches"])
cb.addBucketField(fields, "item_count", bs["itemCount"])
cb.addBucketField(fields, "disk_used", bs["diskUsed"])
cb.addBucketField(fields, "data_used", bs["dataUsed"])
cb.addBucketField(fields, "mem_used", bs["memUsed"])
for name, bucket := range pool.BucketMap {
cluster := regexpURI.ReplaceAllString(addr, "${1}")
err := cb.gatherDetailedBucketStats(addr, bucketName, fields)
if err != nil {
return err
if cb.ClusterBucketStats {
fields := cb.basicBucketStats(bucket.BasicStats)
tags := map[string]string{"cluster": cluster, "bucket": name}
err := cb.gatherDetailedBucketStats(addr, name, nil, fields)
if err != nil {
return err
}
acc.AddFields("couchbase_bucket", fields, tags)
}
acc.AddFields("couchbase_bucket", fields, tags)
if cb.NodeBucketStats {
for _, node := range bucket.Nodes() {
fields := cb.basicBucketStats(bucket.BasicStats)
tags := map[string]string{"cluster": cluster, "bucket": name, "hostname": node.Hostname}
err := cb.gatherDetailedBucketStats(addr, name, &node.Hostname, fields)
if err != nil {
return err
}
acc.AddFields("couchbase_node_bucket", fields, tags)
}
}
}
return nil
}
func (cb *Couchbase) gatherDetailedBucketStats(server, bucket string, fields map[string]interface{}) error {
// basicBucketStats gets the basic bucket statistics
func (cb *Couchbase) basicBucketStats(basicStats map[string]interface{}) map[string]interface{} {
fields := make(map[string]interface{})
cb.addBucketField(fields, "quota_percent_used", basicStats["quotaPercentUsed"])
cb.addBucketField(fields, "ops_per_sec", basicStats["opsPerSec"])
cb.addBucketField(fields, "disk_fetches", basicStats["diskFetches"])
cb.addBucketField(fields, "item_count", basicStats["itemCount"])
cb.addBucketField(fields, "disk_used", basicStats["diskUsed"])
cb.addBucketField(fields, "data_used", basicStats["dataUsed"])
cb.addBucketField(fields, "mem_used", basicStats["memUsed"])
return fields
}
func (cb *Couchbase) gatherDetailedBucketStats(server, bucket string, nodeHostname *string, fields map[string]interface{}) error {
extendedBucketStats := &BucketStats{}
err := cb.queryDetailedBucketStats(server, bucket, extendedBucketStats)
err := cb.queryDetailedBucketStats(server, bucket, nodeHostname, extendedBucketStats)
if err != nil {
return err
}
@ -349,9 +375,15 @@ func (cb *Couchbase) addBucketFieldChecked(fields map[string]interface{}, fieldK
cb.addBucketField(fields, fieldKey, values[len(values)-1])
}
func (cb *Couchbase) queryDetailedBucketStats(server, bucket string, bucketStats *BucketStats) error {
func (cb *Couchbase) queryDetailedBucketStats(server, bucket string, nodeHostname *string, bucketStats *BucketStats) error {
url := server + "/pools/default/buckets/" + bucket
if nodeHostname != nil {
url += "/nodes/" + *nodeHostname
}
url += "/stats?"
// Set up an HTTP request to get the complete set of bucket stats.
req, err := http.NewRequest("GET", server+"/pools/default/buckets/"+bucket+"/stats?", nil)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
@ -399,6 +431,7 @@ func init() {
inputs.Add("couchbase", func() telegraf.Input {
return &Couchbase{
BucketStatsIncluded: []string{"quota_percent_used", "ops_per_sec", "disk_fetches", "item_count", "disk_used", "data_used", "mem_used"},
ClusterBucketStats: true,
}
})
}

File diff suppressed because one or more lines are too long