Skip to content

Commit

Permalink
feat(inputs.couchbase): Add failover metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
powersj committed Aug 29, 2023
1 parent 1d24efe commit 96a010f
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 9 deletions.
60 changes: 53 additions & 7 deletions plugins/inputs/couchbase/couchbase.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package couchbase
import (
_ "embed"
"encoding/json"
"fmt"
"net/http"
"regexp"
"sync"
Expand All @@ -21,19 +22,25 @@ import (
var sampleConfig string

type Couchbase struct {
Servers []string

Servers []string `toml:"servers"`
BucketStatsIncluded []string `toml:"bucket_stats_included"`

ClusterBucketStats bool `toml:"cluster_bucket_stats"`
NodeBucketStats bool `toml:"node_bucket_stats"`
ClusterBucketStats bool `toml:"cluster_bucket_stats"`
NodeBucketStats bool `toml:"node_bucket_stats"`
AutoFailoverStats bool `toml:"autofailover_stats"`

bucketInclude filter.Filter
client *http.Client

tls.ClientConfig
}

type autoFailover struct {
Count int `json:"count"`
Enabled bool `json:"enabled"`
MaxCount int `json:"maxCount"`
Timeout int `json:"timeout"`
}

var regexpURI = regexp.MustCompile(`(\S+://)?(\S+\:\S+@)`)

func (*Couchbase) SampleConfig() string {
Expand Down Expand Up @@ -87,9 +94,8 @@ func (cb *Couchbase) gatherServer(acc telegraf.Accumulator, addr string) error {
acc.AddFields("couchbase_node", fields, tags)
}

cluster := regexpURI.ReplaceAllString(addr, "${1}")
for name, bucket := range pool.BucketMap {
cluster := regexpURI.ReplaceAllString(addr, "${1}")

if cb.ClusterBucketStats {
fields := cb.basicBucketStats(bucket.BasicStats)
tags := map[string]string{"cluster": cluster, "bucket": name}
Expand Down Expand Up @@ -117,9 +123,49 @@ func (cb *Couchbase) gatherServer(acc telegraf.Accumulator, addr string) error {
}
}

if cb.AutoFailoverStats {
tags := map[string]string{"cluster": cluster}
fields, err := cb.gatherAutoFailoverStats(addr)
if err != nil {
return fmt.Errorf("unable to collect autofailover settings: %w", err)
}

acc.AddFields("couchbase_node_autofailover", fields, tags)
}

return nil
}

func (cb *Couchbase) gatherAutoFailoverStats(server string) (map[string]any, error) {
var fields map[string]any

url := server + "/settings/autoFailover"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return fields, err
}

r, err := cb.client.Do(req)
if err != nil {
return fields, err
}
defer r.Body.Close()

var stats autoFailover
if err := json.NewDecoder(r.Body).Decode(&stats); err != nil {
return fields, err
}

fields = map[string]any{
"count": stats.Count,
"enabled": stats.Enabled,
"max_count": stats.MaxCount,
"timeout": stats.Timeout,
}

return fields, nil
}

// basicBucketStats gets the basic bucket statistics
func (cb *Couchbase) basicBucketStats(basicStats map[string]interface{}) map[string]interface{} {
fields := make(map[string]interface{})
Expand Down
44 changes: 44 additions & 0 deletions plugins/inputs/couchbase/couchbase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,50 @@ func TestGatherNodeOnly(t *testing.T) {
acc.AssertDoesNotContainMeasurement(t, "couchbase_bucket")
}

func TestGatherFailover(t *testing.T) {
faker := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/pools":
_, _ = w.Write(readJSON(t, "testdata/pools_response.json"))
case "/pools/default":
_, _ = w.Write(readJSON(t, "testdata/pools_default_response.json"))
case "/pools/default/buckets":
_, _ = w.Write(readJSON(t, "testdata/bucket_response.json"))
case "/settings/autoFailover":
_, _ = w.Write(readJSON(t, "testdata/settings_autofailover.json"))
default:
w.WriteHeader(http.StatusNotFound)
}
}))

cb := Couchbase{
Servers: []string{faker.URL},
ClusterBucketStats: false,
NodeBucketStats: false,
AutoFailoverStats: true,
}
require.NoError(t, cb.Init())

var acc testutil.Accumulator
require.NoError(t, cb.gatherServer(&acc, faker.URL))
require.Equal(t, 0, len(acc.Errors))
require.Equal(t, 8, len(acc.Metrics))

var metric *testutil.Metric
for _, m := range acc.Metrics {
if m.Measurement == "couchbase_node_autofailover" {
metric = m
break
}
}

require.NotNil(t, metric)
require.Equal(t, 1, metric.Fields["count"])
require.Equal(t, true, metric.Fields["enabled"])
require.Equal(t, 2, metric.Fields["max_count"])
require.Equal(t, 72, metric.Fields["timeout"])
}

func readJSON(t *testing.T, jsonFilePath string) []byte {
data, err := os.ReadFile(jsonFilePath)
require.NoErrorf(t, err, "could not read from data file %s", jsonFilePath)
Expand Down
7 changes: 5 additions & 2 deletions plugins/inputs/couchbase/sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
## 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
# cluster_bucket_stats = true

## Whether to collect bucket stats for each individual node
node_bucket_stats = false
# node_bucket_stats = false

## Whether to collect auto-failover settings
# autofailover_stats = false

0 comments on commit 96a010f

Please sign in to comment.