summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/pika/collect_info.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/pika/collect_info.go219
1 files changed, 219 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/pika/collect_info.go b/src/go/collectors/go.d.plugin/modules/pika/collect_info.go
new file mode 100644
index 000000000..2dc68f529
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/pika/collect_info.go
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package pika
+
+import (
+ "bufio"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+)
+
+// https://github.com/Qihoo360/pika/blob/master/src/pika_admin.cc
+// https://github.com/Qihoo360/pika/blob/a0dbdcf5897dd7800ba8a4d1eafce1595619ddc8/src/pika_admin.cc#L694-L710
+
+const (
+ infoSectionServer = "# Server"
+ infoSectionData = "# Data"
+ infoSectionClients = "# Clients"
+ infoSectionStats = "# Stats"
+ infoSectionCommandExecCount = "# Command_Exec_Count"
+ infoSectionCPU = "# CPU"
+ infoSectionReplMaster = "# Replication(MASTER)"
+ infoSectionReplSlave = "# Replication(SLAVE)"
+ infoSectionReplMasterSlave = "# Replication(Master && SLAVE)"
+ infoSectionKeyspace = "# Keyspace"
+)
+
+var infoSections = map[string]struct{}{
+ infoSectionServer: {},
+ infoSectionData: {},
+ infoSectionClients: {},
+ infoSectionStats: {},
+ infoSectionCommandExecCount: {},
+ infoSectionCPU: {},
+ infoSectionReplMaster: {},
+ infoSectionReplSlave: {},
+ infoSectionReplMasterSlave: {},
+ infoSectionKeyspace: {},
+}
+
+func isInfoSection(line string) bool { _, ok := infoSections[line]; return ok }
+
+func (p *Pika) collectInfo(ms map[string]int64, info string) {
+ var curSection string
+
+ sc := bufio.NewScanner(strings.NewReader(info))
+ for sc.Scan() {
+ line := strings.TrimSpace(sc.Text())
+ if len(line) == 0 {
+ curSection = ""
+ continue
+ }
+ if strings.HasPrefix(line, "#") {
+ if isInfoSection(line) {
+ curSection = line
+ }
+ continue
+ }
+
+ field, value, ok := parseProperty(line)
+ if !ok {
+ continue
+ }
+
+ switch curSection {
+ case infoSectionCommandExecCount:
+ p.collectInfoCommandExecCountProperty(ms, field, value)
+ case infoSectionKeyspace:
+ p.collectInfoKeyspaceProperty(ms, field, value)
+ default:
+ collectNumericValue(ms, field, value)
+ }
+ }
+}
+
+var reKeyspaceValue = regexp.MustCompile(`^(.+)_keys=(\d+), expires=(\d+), invalid_keys=(\d+)`)
+
+func (p *Pika) collectInfoKeyspaceProperty(ms map[string]int64, field, value string) {
+ match := reKeyspaceValue.FindStringSubmatch(value)
+ if match == nil {
+ return
+ }
+
+ dataType, keys, expires, invalid := strings.ToLower(match[1]), match[2], match[3], match[4]
+ collectNumericValue(ms, field+"_"+dataType+"_keys", keys)
+ collectNumericValue(ms, field+"_"+dataType+"_expires_keys", expires)
+ collectNumericValue(ms, field+"_"+dataType+"_invalid_keys", invalid)
+
+ if !p.collectedDbs[field] {
+ p.collectedDbs[field] = true
+ p.addDbToKeyspaceCharts(field)
+ }
+}
+
+func (p *Pika) collectInfoCommandExecCountProperty(ms map[string]int64, field, value string) {
+ collectNumericValue(ms, "cmd_"+field+"_calls", value)
+
+ if !p.collectedCommands[field] {
+ p.collectedCommands[field] = true
+ p.addCmdToCommandsCharts(field)
+ }
+}
+
+func (p *Pika) addCmdToCommandsCharts(cmd string) {
+ p.addDimToChart(chartCommandsCalls.ID, &module.Dim{
+ ID: "cmd_" + cmd + "_calls",
+ Name: cmd,
+ Algo: module.Incremental,
+ })
+}
+
+func (p *Pika) addDbToKeyspaceCharts(db string) {
+ p.addDimToChart(chartDbStringsKeys.ID, &module.Dim{
+ ID: db + "_strings_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbStringsExpiresKeys.ID, &module.Dim{
+ ID: db + "_strings_expires_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbStringsInvalidKeys.ID, &module.Dim{
+ ID: db + "_strings_invalid_keys",
+ Name: db,
+ })
+
+ p.addDimToChart(chartDbHashesKeys.ID, &module.Dim{
+ ID: db + "_hashes_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbHashesExpiresKeys.ID, &module.Dim{
+ ID: db + "_hashes_expires_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbHashesInvalidKeys.ID, &module.Dim{
+ ID: db + "_hashes_invalid_keys",
+ Name: db,
+ })
+
+ p.addDimToChart(chartDbListsKeys.ID, &module.Dim{
+ ID: db + "_lists_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbListsExpiresKeys.ID, &module.Dim{
+ ID: db + "_lists_expires_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbListsInvalidKeys.ID, &module.Dim{
+ ID: db + "_lists_invalid_keys",
+ Name: db,
+ })
+
+ p.addDimToChart(chartDbZsetsKeys.ID, &module.Dim{
+ ID: db + "_zsets_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbZsetsExpiresKeys.ID, &module.Dim{
+ ID: db + "_zsets_expires_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbZsetsInvalidKeys.ID, &module.Dim{
+ ID: db + "_zsets_invalid_keys",
+ Name: db,
+ })
+
+ p.addDimToChart(chartDbSetsKeys.ID, &module.Dim{
+ ID: db + "_sets_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbSetsExpiresKeys.ID, &module.Dim{
+ ID: db + "_sets_expires_keys",
+ Name: db,
+ })
+ p.addDimToChart(chartDbSetsInvalidKeys.ID, &module.Dim{
+ ID: db + "_sets_invalid_keys",
+ Name: db,
+ })
+}
+
+func (p *Pika) addDimToChart(chartID string, dim *module.Dim) {
+ chart := p.Charts().Get(chartID)
+ if chart == nil {
+ p.Warningf("error on adding '%s' dimension: can not find '%s' chart", dim.ID, chartID)
+ return
+ }
+ if err := chart.AddDim(dim); err != nil {
+ p.Warning(err)
+ return
+ }
+ chart.MarkNotCreated()
+}
+
+func parseProperty(prop string) (field, value string, ok bool) {
+ var sep byte
+ if strings.HasPrefix(prop, "db") {
+ sep = ' '
+ } else {
+ sep = ':'
+ }
+ i := strings.IndexByte(prop, sep)
+ if i == -1 {
+ return "", "", false
+ }
+ field, value = prop[:i], prop[i+1:]
+ return field, value, field != "" && value != ""
+}
+
+func collectNumericValue(ms map[string]int64, field, value string) {
+ v, err := strconv.ParseFloat(value, 64)
+ if err != nil {
+ return
+ }
+ if strings.IndexByte(value, '.') == -1 {
+ ms[field] = int64(v)
+ } else {
+ ms[field] = int64(v * precision)
+ }
+}