Skip to content

Commit

Permalink
Merge branch '2411-iss' into 'dev'
Browse files Browse the repository at this point in the history
fix: fix crach on input redis

See merge request cloudcare-tools/datakit!3219
  • Loading branch information
谭彪 committed Sep 24, 2024
2 parents 9d60ca7 + dad4be2 commit 3087146
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 34 deletions.
30 changes: 20 additions & 10 deletions internal/plugins/inputs/redis/metric_command_stat.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,46 +42,56 @@ func (m *commandMeasurement) Info() *inputs.MeasurementInfo {
}

func (ipt *Input) parseCommandData(list string) ([]*point.Point, error) {
collectCache := []*point.Point{}
opts := point.DefaultMetricOptions()
opts = append(opts, point.WithTime(time.Now()))
var (
collectCache = []*point.Point{}
rdr = strings.NewReader(list)
scanner = bufio.NewScanner(rdr)
opts = append(point.DefaultMetricOptions(), point.WithTime(time.Now()))
)

rdr := strings.NewReader(list)
scanner := bufio.NewScanner(rdr)
for scanner.Scan() {
var kvs point.KVs

line := scanner.Text()
if len(line) == 0 || line[0] == '#' {
l.Warnf("ignore comment or empty line %q", line)
continue
}

parts := strings.Split(line, ":")
if len(parts) != 2 {
l.Warnf("ignore line %q", line)
continue
}

// example data:
// cmdstat_client|list:calls=1,usec=25,usec_per_call=25.00,rejected_calls=0,failed_calls=0
var kvs point.KVs
kvs = kvs.AddTag("method", parts[0])

itemStrs := strings.Split(parts[1], ",")
for _, itemStr := range itemStrs {
item := strings.Split(itemStr, "=")
arr := strings.Split(itemStr, "=")

if len(arr) != 2 {
l.Warnf("ignore itemStr %q within %q", itemStr, parts[1])
continue
}

f, err := strconv.ParseFloat(item[1], 64)
f, err := strconv.ParseFloat(arr[1], 64)
if err != nil {
l.Warnf("ignore value %q on key %q within %q", arr[1], arr[0], parts[1])
continue
}

kvs = kvs.Add(item[0], f, false, false)
kvs = kvs.Add(arr[0], f, false, false)
}

if kvs.FieldCount() > 0 {
for k, v := range ipt.mergedTags {
kvs = kvs.AddTag(k, v)
}
collectCache = append(collectCache, point.NewPointV2(redisCommandStat, kvs, opts...))
} else {
l.Warnf("no field, ignored line %q", line)
}
}

Expand Down
78 changes: 54 additions & 24 deletions internal/plugins/inputs/redis/metric_command_stat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,24 @@ package redis
import (
"sort"
"strings"
"testing"
T "testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/datakit"
"gitlab.jiagouyun.com/cloudcare-tools/datakit/internal/testutils"
)

func TestInput_parseCommandData(t *testing.T) {
func TestInput_parseCommandData(t *T.T) {
mockCommandData01 := `cmdstat_client|list:calls=1,usec=25,usec_per_call=25.00,rejected_calls=0,failed_calls=0
cmdstat_cluster|info:calls=2,usec=93,usec_per_call=46.50,rejected_calls=0,failed_calls=0
cmdstat_info:calls=5,usec=378,usec_per_call=75.60,rejected_calls=0,failed_calls=0
cmdstat_ping:calls=1,usec=6,usec_per_call=6.00,rejected_calls=0,failed_calls=0
cmdstat_command|docs:calls=2,usec=4112,usec_per_call=2056.00,rejected_calls=0,failed_calls=0
`

type fields struct {
Host string
Tags map[string]string
Expand All @@ -27,11 +36,10 @@ func TestInput_parseCommandData(t *testing.T) {
list string
}
tests := []struct {
name string
fields fields
args args
want []string
wantErr bool
name string
fields fields
args args
want []string
}{
{
name: "no election",
Expand All @@ -51,7 +59,6 @@ func TestInput_parseCommandData(t *testing.T) {
"redis_command_stat,foo=bar,host=HOST,method=cmdstat_info calls=5,failed_calls=0,rejected_calls=0,usec=378,usec_per_call=75.6",
"redis_command_stat,foo=bar,host=HOST,method=cmdstat_ping calls=1,failed_calls=0,rejected_calls=0,usec=6,usec_per_call=6",
},
wantErr: false,
},
{
name: "election",
Expand All @@ -71,11 +78,10 @@ func TestInput_parseCommandData(t *testing.T) {
"redis_command_stat,election=TRUE,foo=bar,method=cmdstat_info calls=5,failed_calls=0,rejected_calls=0,usec=378,usec_per_call=75.6",
"redis_command_stat,election=TRUE,foo=bar,method=cmdstat_ping calls=1,failed_calls=0,rejected_calls=0,usec=6,usec_per_call=6",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(t *T.T) {
ipt := &Input{
Host: tt.fields.Host,
Tags: tt.fields.Tags,
Expand All @@ -86,13 +92,7 @@ func TestInput_parseCommandData(t *testing.T) {
ipt.setup()

got, err := ipt.parseCommandData(tt.args.list)
if (err != nil) != tt.wantErr {
t.Errorf("Input.parseCommandData() error = %v, wantErr %v", err, tt.wantErr)
return
}
if err != nil {
return
}
require.NoError(t, err)

gotStr := []string{}
for _, v := range got {
Expand All @@ -105,11 +105,41 @@ func TestInput_parseCommandData(t *testing.T) {
assert.Equal(t, tt.want, gotStr)
})
}
}

var mockCommandData01 = `cmdstat_client|list:calls=1,usec=25,usec_per_call=25.00,rejected_calls=0,failed_calls=0
cmdstat_cluster|info:calls=2,usec=93,usec_per_call=46.50,rejected_calls=0,failed_calls=0
cmdstat_info:calls=5,usec=378,usec_per_call=75.60,rejected_calls=0,failed_calls=0
cmdstat_ping:calls=1,usec=6,usec_per_call=6.00,rejected_calls=0,failed_calls=0
cmdstat_command|docs:calls=2,usec=4112,usec_per_call=2056.00,rejected_calls=0,failed_calls=0
`
t.Run("ignore-bad-command", func(t *T.T) {
badCommand := `# invalid value
cmdstat_client|list:calls=1,usec=25,usec_per_call=25.00,rejected_calls=0,failed_calls=,invalid=1=2
# no command details: ignored
cmdstat_client|list
# point no fields: ignored
cmdstat_client|list:calls=
# key got no value
cmdstat_client|list:calls=1,usec=25,usec_per_call=25.00,rejected_calls,failed_calls=0`

ipt := &Input{
tagger: testutils.DefaultMockTagger(),
}

ipt.setup()

got, err := ipt.parseCommandData(badCommand)
for _, pt := range got {
pt.SetTime(time.Unix(0, 123))
}

require.NoError(t, err)
assert.Len(t, got, 2)
assert.Equal(t,
"redis_command_stat,host=HOST,method=cmdstat_client|list calls=1,rejected_calls=0,usec=25,usec_per_call=25 123",
got[0].LineProto(),
)

assert.Equal(t,
"redis_command_stat,host=HOST,method=cmdstat_client|list calls=1,failed_calls=0,usec=25,usec_per_call=25 123",
got[1].LineProto(),
)
})
}

0 comments on commit 3087146

Please sign in to comment.