184 lines
4.0 KiB
Go
184 lines
4.0 KiB
Go
package aerospike
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/influxdata/telegraf"
|
|
tlsint "github.com/influxdata/telegraf/internal/tls"
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
|
|
|
as "github.com/aerospike/aerospike-client-go"
|
|
)
|
|
|
|
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 in 1.7; use enable_tls
|
|
tlsint.ClientConfig
|
|
|
|
initialized bool
|
|
tlsConfig *tls.Config
|
|
}
|
|
|
|
var sampleConfig = `
|
|
## 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"
|
|
## If false, skip chain & host verification
|
|
# insecure_skip_verify = true
|
|
`
|
|
|
|
func (a *Aerospike) SampleConfig() string {
|
|
return sampleConfig
|
|
}
|
|
|
|
func (a *Aerospike) Description() string {
|
|
return "Read stats from aerospike server(s)"
|
|
}
|
|
|
|
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 len(a.Servers) == 0 {
|
|
return a.gatherServer("127.0.0.1:3000", acc)
|
|
}
|
|
|
|
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(serv, acc))
|
|
}(server)
|
|
}
|
|
|
|
wg.Wait()
|
|
return nil
|
|
}
|
|
|
|
func (a *Aerospike) gatherServer(hostport string, acc telegraf.Accumulator) error {
|
|
host, port, err := net.SplitHostPort(hostport)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
iport, err := strconv.Atoi(port)
|
|
if err != nil {
|
|
iport = 3000
|
|
}
|
|
|
|
policy := as.NewClientPolicy()
|
|
policy.User = a.Username
|
|
policy.Password = a.Password
|
|
policy.TlsConfig = a.tlsConfig
|
|
c, err := as.NewClientWithPolicy(policy, host, iport)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer c.Close()
|
|
|
|
nodes := c.GetNodes()
|
|
for _, n := range nodes {
|
|
tags := map[string]string{
|
|
"aerospike_host": hostport,
|
|
"node_name": n.GetName(),
|
|
}
|
|
fields := make(map[string]interface{})
|
|
stats, err := as.RequestNodeStats(n)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for k, v := range stats {
|
|
val := parseValue(v)
|
|
fields[strings.Replace(k, "-", "_", -1)] = val
|
|
}
|
|
acc.AddFields("aerospike_node", fields, tags, time.Now())
|
|
|
|
info, err := as.RequestNodeInfo(n, "namespaces")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
namespaces := strings.Split(info["namespaces"], ";")
|
|
|
|
for _, namespace := range namespaces {
|
|
nTags := map[string]string{
|
|
"aerospike_host": hostport,
|
|
"node_name": n.GetName(),
|
|
}
|
|
nTags["namespace"] = namespace
|
|
nFields := make(map[string]interface{})
|
|
info, err := as.RequestNodeInfo(n, "namespace/"+namespace)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
stats := strings.Split(info["namespace/"+namespace], ";")
|
|
for _, stat := range stats {
|
|
parts := strings.Split(stat, "=")
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
val := parseValue(parts[1])
|
|
nFields[strings.Replace(parts[0], "-", "_", -1)] = val
|
|
}
|
|
acc.AddFields("aerospike_namespace", nFields, nTags, time.Now())
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseValue(v string) interface{} {
|
|
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 {
|
|
// leave as string
|
|
return v
|
|
}
|
|
}
|
|
|
|
func copyTags(m map[string]string) map[string]string {
|
|
out := make(map[string]string)
|
|
for k, v := range m {
|
|
out[k] = v
|
|
}
|
|
return out
|
|
}
|
|
|
|
func init() {
|
|
inputs.Add("aerospike", func() telegraf.Input {
|
|
return &Aerospike{}
|
|
})
|
|
}
|