Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
173
plugins/inputs/aerospike/README.md
Normal file
173
plugins/inputs/aerospike/README.md
Normal file
File diff suppressed because one or more lines are too long
457
plugins/inputs/aerospike/aerospike.go
Normal file
457
plugins/inputs/aerospike/aerospike.go
Normal file
|
@ -0,0 +1,457 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package aerospike
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
as "github.com/aerospike/aerospike-client-go/v5"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
common_tls "github.com/influxdata/telegraf/plugins/common/tls"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
type Aerospike struct {
|
||||
Servers []string `toml:"servers"`
|
||||
|
||||
Username string `toml:"username"`
|
||||
Password string `toml:"password"`
|
||||
|
||||
EnableTLS bool `toml:"enable_tls"`
|
||||
EnableSSL bool `toml:"enable_ssl" deprecated:"1.7.0;1.35.0;use 'enable_tls' instead"`
|
||||
TLSName string `toml:"tls_name"`
|
||||
common_tls.ClientConfig
|
||||
|
||||
initialized bool
|
||||
tlsConfig *tls.Config
|
||||
|
||||
DisableQueryNamespaces bool `toml:"disable_query_namespaces"`
|
||||
Namespaces []string `toml:"namespaces"`
|
||||
|
||||
QuerySets bool `toml:"query_sets"`
|
||||
Sets []string `toml:"sets"`
|
||||
|
||||
EnableTTLHistogram bool `toml:"enable_ttl_histogram"`
|
||||
EnableObjectSizeLinearHistogram bool `toml:"enable_object_size_linear_histogram"`
|
||||
|
||||
NumberHistogramBuckets int `toml:"num_histogram_buckets"`
|
||||
}
|
||||
|
||||
// On the random chance a hex value is all digits
|
||||
// these are fields that can contain hex and should always be strings
|
||||
var protectedHexFields = map[string]bool{
|
||||
"node_name": true,
|
||||
"cluster_key": true,
|
||||
"paxos_principal": true,
|
||||
}
|
||||
|
||||
func (*Aerospike) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (a *Aerospike) Gather(acc telegraf.Accumulator) error {
|
||||
if !a.initialized {
|
||||
tlsConfig, err := a.ClientConfig.TLSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tlsConfig == nil && (a.EnableTLS || a.EnableSSL) {
|
||||
tlsConfig = &tls.Config{}
|
||||
}
|
||||
a.tlsConfig = tlsConfig
|
||||
a.initialized = true
|
||||
}
|
||||
|
||||
if a.NumberHistogramBuckets == 0 {
|
||||
a.NumberHistogramBuckets = 10
|
||||
} else if a.NumberHistogramBuckets > 100 {
|
||||
a.NumberHistogramBuckets = 100
|
||||
} else if a.NumberHistogramBuckets < 1 {
|
||||
a.NumberHistogramBuckets = 10
|
||||
}
|
||||
|
||||
if len(a.Servers) == 0 {
|
||||
return a.gatherServer(acc, "127.0.0.1:3000")
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(a.Servers))
|
||||
for _, server := range a.Servers {
|
||||
go func(serv string) {
|
||||
defer wg.Done()
|
||||
acc.AddError(a.gatherServer(acc, serv))
|
||||
}(server)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Aerospike) gatherServer(acc telegraf.Accumulator, hostPort string) error {
|
||||
policy := as.NewClientPolicy()
|
||||
policy.User = a.Username
|
||||
policy.Password = a.Password
|
||||
policy.TlsConfig = a.tlsConfig
|
||||
asHosts, err := as.NewHosts(hostPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if a.TLSName != "" && (a.EnableTLS || a.EnableSSL) {
|
||||
for _, asHost := range asHosts {
|
||||
asHost.TLSName = a.TLSName
|
||||
}
|
||||
}
|
||||
c, err := as.NewClientWithPolicyAndHost(policy, asHosts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
asInfoPolicy := as.NewInfoPolicy()
|
||||
defer c.Close()
|
||||
|
||||
nodes := c.GetNodes()
|
||||
for _, n := range nodes {
|
||||
nodeHost := n.GetHost().String()
|
||||
stats, err := getNodeInfo(n, asInfoPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parseNodeInfo(acc, stats, nodeHost, n.GetName())
|
||||
|
||||
namespaces, err := a.getNamespaces(n, asInfoPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !a.DisableQueryNamespaces {
|
||||
// Query Namespaces
|
||||
for _, namespace := range namespaces {
|
||||
stats, err = getNamespaceInfo(namespace, n, asInfoPolicy)
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
parseNamespaceInfo(acc, stats, nodeHost, namespace, n.GetName())
|
||||
|
||||
if a.EnableTTLHistogram {
|
||||
err = a.getTTLHistogram(acc, nodeHost, namespace, "", n, asInfoPolicy)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if a.EnableObjectSizeLinearHistogram {
|
||||
err = a.getObjectSizeLinearHistogram(acc, nodeHost, namespace, "", n, asInfoPolicy)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if a.QuerySets {
|
||||
namespaceSets, err := a.getSets(n, asInfoPolicy)
|
||||
if err == nil {
|
||||
for _, namespaceSet := range namespaceSets {
|
||||
namespace, set := splitNamespaceSet(namespaceSet)
|
||||
stats, err := getSetInfo(namespaceSet, n, asInfoPolicy)
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
parseSetInfo(acc, stats, nodeHost, namespaceSet, n.GetName())
|
||||
|
||||
if a.EnableTTLHistogram {
|
||||
err = a.getTTLHistogram(acc, nodeHost, namespace, set, n, asInfoPolicy)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if a.EnableObjectSizeLinearHistogram {
|
||||
err = a.getObjectSizeLinearHistogram(acc, nodeHost, namespace, set, n, asInfoPolicy)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNodeInfo(n *as.Node, infoPolicy *as.InfoPolicy) (map[string]string, error) {
|
||||
stats, err := n.RequestInfo(infoPolicy, "statistics")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func parseNodeInfo(acc telegraf.Accumulator, stats map[string]string, hostPort, nodeName string) {
|
||||
nTags := map[string]string{
|
||||
"aerospike_host": hostPort,
|
||||
"node_name": nodeName,
|
||||
}
|
||||
nFields := make(map[string]interface{})
|
||||
stat := strings.Split(stats["statistics"], ";")
|
||||
for _, pair := range stat {
|
||||
parts := strings.Split(pair, "=")
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
key := strings.ReplaceAll(parts[0], "-", "_")
|
||||
nFields[key] = parseAerospikeValue(key, parts[1])
|
||||
}
|
||||
acc.AddFields("aerospike_node", nFields, nTags, time.Now())
|
||||
}
|
||||
|
||||
func (a *Aerospike) getNamespaces(n *as.Node, infoPolicy *as.InfoPolicy) ([]string, error) {
|
||||
var namespaces []string
|
||||
if len(a.Namespaces) == 0 {
|
||||
info, err := n.RequestInfo(infoPolicy, "namespaces")
|
||||
if err != nil {
|
||||
return namespaces, err
|
||||
}
|
||||
namespaces = strings.Split(info["namespaces"], ";")
|
||||
} else {
|
||||
namespaces = a.Namespaces
|
||||
}
|
||||
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
func getNamespaceInfo(namespace string, n *as.Node, infoPolicy *as.InfoPolicy) (map[string]string, error) {
|
||||
stats, err := n.RequestInfo(infoPolicy, "namespace/"+namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stats, err
|
||||
}
|
||||
|
||||
func parseNamespaceInfo(acc telegraf.Accumulator, stats map[string]string, hostPort, namespace, nodeName string) {
|
||||
nTags := map[string]string{
|
||||
"aerospike_host": hostPort,
|
||||
"node_name": nodeName,
|
||||
}
|
||||
nTags["namespace"] = namespace
|
||||
nFields := make(map[string]interface{})
|
||||
|
||||
stat := strings.Split(stats["namespace/"+namespace], ";")
|
||||
for _, pair := range stat {
|
||||
parts := strings.Split(pair, "=")
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
key := strings.ReplaceAll(parts[0], "-", "_")
|
||||
nFields[key] = parseAerospikeValue(key, parts[1])
|
||||
}
|
||||
acc.AddFields("aerospike_namespace", nFields, nTags, time.Now())
|
||||
}
|
||||
|
||||
func (a *Aerospike) getSets(n *as.Node, infoPolicy *as.InfoPolicy) ([]string, error) {
|
||||
var namespaceSets []string
|
||||
// Gather all sets
|
||||
if len(a.Sets) == 0 {
|
||||
stats, err := n.RequestInfo(infoPolicy, "sets")
|
||||
if err != nil {
|
||||
return namespaceSets, err
|
||||
}
|
||||
stat := strings.Split(stats["sets"], ";")
|
||||
for _, setStats := range stat {
|
||||
// setInfo is "ns=test:set=foo:objects=1:tombstones=0"
|
||||
if len(setStats) > 0 {
|
||||
pairs := strings.Split(setStats, ":")
|
||||
var ns, set string
|
||||
for _, pair := range pairs {
|
||||
parts := strings.Split(pair, "=")
|
||||
if len(parts) == 2 {
|
||||
if parts[0] == "ns" {
|
||||
ns = parts[1]
|
||||
}
|
||||
if parts[0] == "set" {
|
||||
set = parts[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(ns) > 0 && len(set) > 0 {
|
||||
namespaceSets = append(namespaceSets, fmt.Sprintf("%s/%s", ns, set))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // User has passed in sets
|
||||
namespaceSets = a.Sets
|
||||
}
|
||||
|
||||
return namespaceSets, nil
|
||||
}
|
||||
|
||||
func getSetInfo(namespaceSet string, n *as.Node, infoPolicy *as.InfoPolicy) (map[string]string, error) {
|
||||
stats, err := n.RequestInfo(infoPolicy, "sets/"+namespaceSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func parseSetInfo(acc telegraf.Accumulator, stats map[string]string, hostPort, namespaceSet, nodeName string) {
|
||||
stat := strings.Split(
|
||||
strings.TrimSuffix(
|
||||
stats["sets/"+namespaceSet], ";"), ":")
|
||||
nTags := map[string]string{
|
||||
"aerospike_host": hostPort,
|
||||
"node_name": nodeName,
|
||||
"set": namespaceSet,
|
||||
}
|
||||
nFields := make(map[string]interface{})
|
||||
for _, part := range stat {
|
||||
pieces := strings.Split(part, "=")
|
||||
if len(pieces) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
key := strings.ReplaceAll(pieces[0], "-", "_")
|
||||
nFields[key] = parseAerospikeValue(key, pieces[1])
|
||||
}
|
||||
acc.AddFields("aerospike_set", nFields, nTags, time.Now())
|
||||
}
|
||||
|
||||
func (a *Aerospike) getTTLHistogram(acc telegraf.Accumulator, hostPort, namespace, set string, n *as.Node, infoPolicy *as.InfoPolicy) error {
|
||||
stats, err := getHistogram(namespace, set, "ttl", n, infoPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nTags := createTags(hostPort, n.GetName(), namespace, set)
|
||||
a.parseHistogram(acc, stats, nTags, "ttl")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Aerospike) getObjectSizeLinearHistogram(acc telegraf.Accumulator, hostPort, namespace, set string, n *as.Node, infoPolicy *as.InfoPolicy) error {
|
||||
stats, err := getHistogram(namespace, set, "object-size-linear", n, infoPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nTags := createTags(hostPort, n.GetName(), namespace, set)
|
||||
a.parseHistogram(acc, stats, nTags, "object-size-linear")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHistogram(namespace, set, histogramType string, n *as.Node, infoPolicy *as.InfoPolicy) (map[string]string, error) {
|
||||
var queryArg string
|
||||
if len(set) > 0 {
|
||||
queryArg = fmt.Sprintf("histogram:type=%s;namespace=%v;set=%v", histogramType, namespace, set)
|
||||
} else {
|
||||
queryArg = fmt.Sprintf("histogram:type=%s;namespace=%v", histogramType, namespace)
|
||||
}
|
||||
|
||||
stats, err := n.RequestInfo(infoPolicy, queryArg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func (a *Aerospike) parseHistogram(acc telegraf.Accumulator, stats, nTags map[string]string, histogramType string) {
|
||||
nFields := make(map[string]interface{})
|
||||
|
||||
for _, stat := range stats {
|
||||
for _, part := range strings.Split(stat, ":") {
|
||||
pieces := strings.Split(part, "=")
|
||||
if len(pieces) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
if pieces[0] == "buckets" {
|
||||
buckets := strings.Split(pieces[1], ",")
|
||||
|
||||
// Normalize in case of less buckets than expected
|
||||
numRecordsPerBucket := 1
|
||||
if len(buckets) > a.NumberHistogramBuckets {
|
||||
numRecordsPerBucket = int(math.Ceil(float64(len(buckets)) / float64(a.NumberHistogramBuckets)))
|
||||
}
|
||||
|
||||
bucketCount := 0
|
||||
bucketSum := int64(0) // cast to int64, as can have large object sums
|
||||
bucketName := 0
|
||||
for i, bucket := range buckets {
|
||||
// Sum records and increment bucket collection counter
|
||||
if bucketCount < numRecordsPerBucket {
|
||||
bucketSum = bucketSum + parseAerospikeValue("", bucket).(int64)
|
||||
bucketCount++
|
||||
}
|
||||
|
||||
// Store records and reset counters
|
||||
// increment bucket name
|
||||
if bucketCount == numRecordsPerBucket {
|
||||
nFields[strconv.Itoa(bucketName)] = bucketSum
|
||||
|
||||
bucketCount = 0
|
||||
bucketSum = 0
|
||||
bucketName++
|
||||
} else if i == (len(buckets) - 1) {
|
||||
// base/edge case where final bucket does not fully
|
||||
// fill number of records per bucket
|
||||
nFields[strconv.Itoa(bucketName)] = bucketSum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acc.AddFields(fmt.Sprintf("aerospike_histogram_%v", strings.ReplaceAll(histogramType, "-", "_")), nFields, nTags, time.Now())
|
||||
}
|
||||
|
||||
func splitNamespaceSet(namespaceSet string) (namespace, set string) {
|
||||
split := strings.Split(namespaceSet, "/")
|
||||
return split[0], split[1]
|
||||
}
|
||||
|
||||
func parseAerospikeValue(key, v string) interface{} {
|
||||
if protectedHexFields[key] {
|
||||
return v
|
||||
} else if parsed, err := strconv.ParseInt(v, 10, 64); err == nil {
|
||||
return parsed
|
||||
} else if parsed, err := strconv.ParseUint(v, 10, 64); err == nil {
|
||||
return parsed
|
||||
} else if parsed, err := strconv.ParseBool(v); err == nil {
|
||||
return parsed
|
||||
} else if parsed, err := strconv.ParseFloat(v, 32); err == nil {
|
||||
return parsed
|
||||
}
|
||||
// leave as string
|
||||
return v
|
||||
}
|
||||
|
||||
func createTags(hostPort, nodeName, namespace, set string) map[string]string {
|
||||
nTags := map[string]string{
|
||||
"aerospike_host": hostPort,
|
||||
"node_name": nodeName,
|
||||
"namespace": namespace,
|
||||
}
|
||||
|
||||
if len(set) > 0 {
|
||||
nTags["set"] = set
|
||||
}
|
||||
return nTags
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("aerospike", func() telegraf.Input {
|
||||
return &Aerospike{}
|
||||
})
|
||||
}
|
480
plugins/inputs/aerospike/aerospike_test.go
Normal file
480
plugins/inputs/aerospike/aerospike_test.go
Normal file
|
@ -0,0 +1,480 @@
|
|||
package aerospike
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
as "github.com/aerospike/aerospike-client-go/v5"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
const servicePort = "3000"
|
||||
|
||||
func launchTestServer(t *testing.T) *testutil.Container {
|
||||
container := testutil.Container{
|
||||
Image: "aerospike:ce-6.0.0.1",
|
||||
ExposedPorts: []string{servicePort},
|
||||
WaitingFor: wait.ForLog("migrations: complete"),
|
||||
}
|
||||
err := container.Start()
|
||||
require.NoError(t, err, "failed to start container")
|
||||
|
||||
return &container
|
||||
}
|
||||
|
||||
func TestAerospikeStatisticsIntegration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping aerospike integration tests.")
|
||||
}
|
||||
|
||||
container := launchTestServer(t)
|
||||
defer container.Terminate()
|
||||
|
||||
a := &Aerospike{
|
||||
Servers: []string{fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort])},
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
err := acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, acc.HasMeasurement("aerospike_node"))
|
||||
require.True(t, acc.HasTag("aerospike_node", "node_name"))
|
||||
require.True(t, acc.HasMeasurement("aerospike_namespace"))
|
||||
require.True(t, acc.HasTag("aerospike_namespace", "node_name"))
|
||||
require.True(t, acc.HasInt64Field("aerospike_node", "batch_index_error"))
|
||||
|
||||
namespaceName := acc.TagValue("aerospike_namespace", "namespace")
|
||||
require.Equal(t, "test", namespaceName)
|
||||
}
|
||||
|
||||
func TestAerospikeStatisticsPartialErrIntegration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping aerospike integration tests.")
|
||||
}
|
||||
|
||||
container := launchTestServer(t)
|
||||
defer container.Terminate()
|
||||
|
||||
a := &Aerospike{
|
||||
Servers: []string{
|
||||
fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort]),
|
||||
testutil.GetLocalHost() + ":9999",
|
||||
},
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := acc.GatherError(a.Gather)
|
||||
|
||||
require.Error(t, err)
|
||||
|
||||
require.True(t, acc.HasMeasurement("aerospike_node"))
|
||||
require.True(t, acc.HasMeasurement("aerospike_namespace"))
|
||||
require.True(t, acc.HasInt64Field("aerospike_node", "batch_index_error"))
|
||||
namespaceName := acc.TagSetValue("aerospike_namespace", "namespace")
|
||||
require.Equal(t, "test", namespaceName)
|
||||
}
|
||||
|
||||
func TestSelectNamespacesIntegration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping aerospike integration tests.")
|
||||
}
|
||||
|
||||
container := launchTestServer(t)
|
||||
defer container.Terminate()
|
||||
|
||||
// Select nonexistent namespace
|
||||
a := &Aerospike{
|
||||
Servers: []string{fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort])},
|
||||
Namespaces: []string{"notTest"},
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
err := acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, acc.HasMeasurement("aerospike_node"))
|
||||
require.True(t, acc.HasTag("aerospike_node", "node_name"))
|
||||
require.True(t, acc.HasMeasurement("aerospike_namespace"))
|
||||
require.True(t, acc.HasTag("aerospike_namespace", "node_name"))
|
||||
|
||||
// Expect only 1 namespace
|
||||
count := 0
|
||||
for _, p := range acc.Metrics {
|
||||
if p.Measurement == "aerospike_namespace" {
|
||||
count++
|
||||
}
|
||||
}
|
||||
require.Equal(t, 1, count)
|
||||
|
||||
// expect namespace to have no fields as nonexistent
|
||||
require.False(t, acc.HasInt64Field("aerospke_namespace", "appeals_tx_remaining"))
|
||||
}
|
||||
|
||||
func TestDisableQueryNamespacesIntegration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping aerospike integration tests.")
|
||||
}
|
||||
|
||||
container := launchTestServer(t)
|
||||
defer container.Terminate()
|
||||
|
||||
a := &Aerospike{
|
||||
Servers: []string{
|
||||
fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort]),
|
||||
},
|
||||
DisableQueryNamespaces: true,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, acc.HasMeasurement("aerospike_node"))
|
||||
require.False(t, acc.HasMeasurement("aerospike_namespace"))
|
||||
|
||||
a.DisableQueryNamespaces = false
|
||||
err = acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, acc.HasMeasurement("aerospike_node"))
|
||||
require.True(t, acc.HasMeasurement("aerospike_namespace"))
|
||||
}
|
||||
|
||||
func TestQuerySetsIntegration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping aerospike integration tests.")
|
||||
}
|
||||
|
||||
container := launchTestServer(t)
|
||||
defer container.Terminate()
|
||||
|
||||
portInt, err := strconv.Atoi(container.Ports[servicePort])
|
||||
require.NoError(t, err)
|
||||
|
||||
// create a set
|
||||
// test is the default namespace from aerospike
|
||||
policy := as.NewClientPolicy()
|
||||
client, errAs := as.NewClientWithPolicy(policy, container.Address, portInt)
|
||||
require.NoError(t, errAs)
|
||||
|
||||
key, errAs := as.NewKey("test", "foo", 123)
|
||||
require.NoError(t, errAs)
|
||||
bins := as.BinMap{
|
||||
"e": 2,
|
||||
"pi": 3,
|
||||
}
|
||||
errAs = client.Add(nil, key, bins)
|
||||
require.NoError(t, errAs)
|
||||
|
||||
key, errAs = as.NewKey("test", "bar", 1234)
|
||||
require.NoError(t, errAs)
|
||||
bins = as.BinMap{
|
||||
"e": 2,
|
||||
"pi": 3,
|
||||
}
|
||||
errAs = client.Add(nil, key, bins)
|
||||
require.NoError(t, errAs)
|
||||
|
||||
a := &Aerospike{
|
||||
Servers: []string{
|
||||
fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort]),
|
||||
},
|
||||
QuerySets: true,
|
||||
DisableQueryNamespaces: true,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err = acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, FindTagValue(&acc, "aerospike_set", "set", "test/foo"))
|
||||
require.True(t, FindTagValue(&acc, "aerospike_set", "set", "test/bar"))
|
||||
|
||||
require.True(t, acc.HasMeasurement("aerospike_set"))
|
||||
require.True(t, acc.HasTag("aerospike_set", "set"))
|
||||
require.True(t, acc.HasInt64Field("aerospike_set", "memory_data_bytes"))
|
||||
}
|
||||
|
||||
func TestSelectQuerySetsIntegration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping aerospike integration tests.")
|
||||
}
|
||||
|
||||
container := launchTestServer(t)
|
||||
defer container.Terminate()
|
||||
|
||||
portInt, err := strconv.Atoi(container.Ports[servicePort])
|
||||
require.NoError(t, err)
|
||||
|
||||
// create a set
|
||||
// test is the default namespace from aerospike
|
||||
policy := as.NewClientPolicy()
|
||||
client, errAs := as.NewClientWithPolicy(policy, container.Address, portInt)
|
||||
require.NoError(t, errAs)
|
||||
|
||||
key, errAs := as.NewKey("test", "foo", 123)
|
||||
require.NoError(t, errAs)
|
||||
bins := as.BinMap{
|
||||
"e": 2,
|
||||
"pi": 3,
|
||||
}
|
||||
errAs = client.Add(nil, key, bins)
|
||||
require.NoError(t, errAs)
|
||||
|
||||
key, errAs = as.NewKey("test", "bar", 1234)
|
||||
require.NoError(t, errAs)
|
||||
bins = as.BinMap{
|
||||
"e": 2,
|
||||
"pi": 3,
|
||||
}
|
||||
errAs = client.Add(nil, key, bins)
|
||||
require.NoError(t, errAs)
|
||||
|
||||
a := &Aerospike{
|
||||
Servers: []string{
|
||||
fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort]),
|
||||
},
|
||||
QuerySets: true,
|
||||
Sets: []string{"test/foo"},
|
||||
DisableQueryNamespaces: true,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err = acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, FindTagValue(&acc, "aerospike_set", "set", "test/foo"))
|
||||
require.False(t, FindTagValue(&acc, "aerospike_set", "set", "test/bar"))
|
||||
|
||||
require.True(t, acc.HasMeasurement("aerospike_set"))
|
||||
require.True(t, acc.HasTag("aerospike_set", "set"))
|
||||
require.True(t, acc.HasInt64Field("aerospike_set", "memory_data_bytes"))
|
||||
}
|
||||
|
||||
func TestDisableTTLHistogramIntegration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping aerospike integration tests.")
|
||||
}
|
||||
|
||||
container := launchTestServer(t)
|
||||
defer container.Terminate()
|
||||
|
||||
a := &Aerospike{
|
||||
Servers: []string{
|
||||
fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort]),
|
||||
},
|
||||
QuerySets: true,
|
||||
EnableTTLHistogram: false,
|
||||
}
|
||||
/*
|
||||
No measurement exists
|
||||
*/
|
||||
var acc testutil.Accumulator
|
||||
err := acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.False(t, acc.HasMeasurement("aerospike_histogram_ttl"))
|
||||
}
|
||||
|
||||
func TestDisableObjectSizeLinearHistogramIntegration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping aerospike integration tests.")
|
||||
}
|
||||
|
||||
container := launchTestServer(t)
|
||||
defer container.Terminate()
|
||||
|
||||
a := &Aerospike{
|
||||
Servers: []string{
|
||||
fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort]),
|
||||
},
|
||||
QuerySets: true,
|
||||
EnableObjectSizeLinearHistogram: false,
|
||||
}
|
||||
/*
|
||||
No Measurement
|
||||
*/
|
||||
var acc testutil.Accumulator
|
||||
err := acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.False(t, acc.HasMeasurement("aerospike_histogram_object_size_linear"))
|
||||
}
|
||||
|
||||
func TestParseNodeInfo(t *testing.T) {
|
||||
stats := map[string]string{
|
||||
"statistics": "early_tsvc_from_proxy_error=0;cluster_principal=BB9020012AC4202;cluster_is_member=true",
|
||||
}
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"early_tsvc_from_proxy_error": int64(0),
|
||||
"cluster_principal": "BB9020012AC4202",
|
||||
"cluster_is_member": true,
|
||||
}
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"aerospike_host": "127.0.0.1:3000",
|
||||
"node_name": "TestNodeName",
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
parseNodeInfo(&acc, stats, "127.0.0.1:3000", "TestNodeName")
|
||||
acc.AssertContainsTaggedFields(t, "aerospike_node", expectedFields, expectedTags)
|
||||
}
|
||||
|
||||
func TestParseNamespaceInfo(t *testing.T) {
|
||||
stats := map[string]string{
|
||||
"namespace/test": "ns_cluster_size=1;effective_replication_factor=1;objects=2;tombstones=0;master_objects=2",
|
||||
}
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"ns_cluster_size": int64(1),
|
||||
"effective_replication_factor": int64(1),
|
||||
"tombstones": int64(0),
|
||||
"objects": int64(2),
|
||||
"master_objects": int64(2),
|
||||
}
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"aerospike_host": "127.0.0.1:3000",
|
||||
"node_name": "TestNodeName",
|
||||
"namespace": "test",
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
parseNamespaceInfo(&acc, stats, "127.0.0.1:3000", "test", "TestNodeName")
|
||||
acc.AssertContainsTaggedFields(t, "aerospike_namespace", expectedFields, expectedTags)
|
||||
}
|
||||
|
||||
func TestParseSetInfo(t *testing.T) {
|
||||
stats := map[string]string{
|
||||
"sets/test/foo": "objects=1:tombstones=0:memory_data_bytes=26;",
|
||||
}
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"objects": int64(1),
|
||||
"tombstones": int64(0),
|
||||
"memory_data_bytes": int64(26),
|
||||
}
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"aerospike_host": "127.0.0.1:3000",
|
||||
"node_name": "TestNodeName",
|
||||
"set": "test/foo",
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
parseSetInfo(&acc, stats, "127.0.0.1:3000", "test/foo", "TestNodeName")
|
||||
acc.AssertContainsTaggedFields(t, "aerospike_set", expectedFields, expectedTags)
|
||||
}
|
||||
|
||||
func TestParseHistogramSet(t *testing.T) {
|
||||
a := &Aerospike{
|
||||
NumberHistogramBuckets: 10,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
stats := map[string]string{
|
||||
"histogram:type=object-size-linear;namespace=test;set=foo": "units=bytes:hist-width=1048576:bucket-width=1024:buckets=0,1,3,1,6,1,9,1,12,1,15,1,18",
|
||||
}
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"0": int64(1),
|
||||
"1": int64(4),
|
||||
"2": int64(7),
|
||||
"3": int64(10),
|
||||
"4": int64(13),
|
||||
"5": int64(16),
|
||||
"6": int64(18),
|
||||
}
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"aerospike_host": "127.0.0.1:3000",
|
||||
"node_name": "TestNodeName",
|
||||
"namespace": "test",
|
||||
"set": "foo",
|
||||
}
|
||||
|
||||
nTags := createTags("127.0.0.1:3000", "TestNodeName", "test", "foo")
|
||||
a.parseHistogram(&acc, stats, nTags, "object-size-linear")
|
||||
acc.AssertContainsTaggedFields(t, "aerospike_histogram_object_size_linear", expectedFields, expectedTags)
|
||||
}
|
||||
|
||||
func TestParseHistogramNamespace(t *testing.T) {
|
||||
a := &Aerospike{
|
||||
NumberHistogramBuckets: 10,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
stats := map[string]string{
|
||||
"histogram:type=object-size-linear;namespace=test;set=foo": " units=bytes:hist-width=1048576:bucket-width=1024:buckets=0,1,3,1,6,1,9,1,12,1,15,1,18",
|
||||
}
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"0": int64(1),
|
||||
"1": int64(4),
|
||||
"2": int64(7),
|
||||
"3": int64(10),
|
||||
"4": int64(13),
|
||||
"5": int64(16),
|
||||
"6": int64(18),
|
||||
}
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"aerospike_host": "127.0.0.1:3000",
|
||||
"node_name": "TestNodeName",
|
||||
"namespace": "test",
|
||||
}
|
||||
|
||||
nTags := createTags("127.0.0.1:3000", "TestNodeName", "test", "")
|
||||
a.parseHistogram(&acc, stats, nTags, "object-size-linear")
|
||||
acc.AssertContainsTaggedFields(t, "aerospike_histogram_object_size_linear", expectedFields, expectedTags)
|
||||
}
|
||||
|
||||
func TestAerospikeParseValue(t *testing.T) {
|
||||
// uint64 with value bigger than int64 max
|
||||
val := parseAerospikeValue("", "18446744041841121751")
|
||||
require.Equal(t, uint64(18446744041841121751), val)
|
||||
|
||||
val = parseAerospikeValue("", "true")
|
||||
v, ok := val.(bool)
|
||||
require.Truef(t, ok, "bool type expected, got '%T' with '%v' value instead", val, val)
|
||||
require.True(t, v)
|
||||
|
||||
// int values
|
||||
val = parseAerospikeValue("", "42")
|
||||
require.Equal(t, int64(42), val, "must be parsed as an int64")
|
||||
|
||||
// string values
|
||||
val = parseAerospikeValue("", "BB977942A2CA502")
|
||||
require.Equal(t, `BB977942A2CA502`, val, "must be left as a string")
|
||||
|
||||
// all digit hex values, unprotected
|
||||
val = parseAerospikeValue("", "1992929191")
|
||||
require.Equal(t, int64(1992929191), val, "must be parsed as an int64")
|
||||
|
||||
// all digit hex values, protected
|
||||
val = parseAerospikeValue("node_name", "1992929191")
|
||||
require.Equal(t, `1992929191`, val, "must be left as a string")
|
||||
}
|
||||
|
||||
func FindTagValue(acc *testutil.Accumulator, measurement, key, value string) bool {
|
||||
for _, p := range acc.Metrics {
|
||||
if p.Measurement == measurement {
|
||||
v, ok := p.Tags[key]
|
||||
if ok && v == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
41
plugins/inputs/aerospike/sample.conf
Normal file
41
plugins/inputs/aerospike/sample.conf
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Read stats from aerospike server(s)
|
||||
[[inputs.aerospike]]
|
||||
## Aerospike servers to connect to (with port)
|
||||
## This plugin will query all namespaces the aerospike
|
||||
## server has configured and get stats for them.
|
||||
servers = ["localhost:3000"]
|
||||
|
||||
# username = "telegraf"
|
||||
# password = "pa$$word"
|
||||
|
||||
## Optional TLS Config
|
||||
# enable_tls = false
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
# tls_name = "tlsname"
|
||||
## If false, skip chain & host verification
|
||||
# insecure_skip_verify = true
|
||||
|
||||
# Feature Options
|
||||
# Add namespace variable to limit the namespaces executed on
|
||||
# Leave blank to do all
|
||||
# disable_query_namespaces = true # default false
|
||||
# namespaces = ["namespace1", "namespace2"]
|
||||
|
||||
# Enable set level telemetry
|
||||
# query_sets = true # default: false
|
||||
# Add namespace set combinations to limit sets executed on
|
||||
# Leave blank to do all sets
|
||||
# sets = ["namespace1/set1", "namespace1/set2", "namespace3"]
|
||||
|
||||
# Histograms
|
||||
# enable_ttl_histogram = true # default: false
|
||||
# enable_object_size_linear_histogram = true # default: false
|
||||
|
||||
# by default, aerospike produces a 100 bucket histogram
|
||||
# this is not great for most graphing tools, this will allow
|
||||
# the ability to squash this to a smaller number of buckets
|
||||
# To have a balanced histogram, the number of buckets chosen
|
||||
# should divide evenly into 100.
|
||||
# num_histogram_buckets = 100 # default: 10
|
Loading…
Add table
Add a link
Reference in a new issue