@@ -10,33 +10,37 @@ import (
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/internal"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
kwAll = "all"
|
||||
)
|
||||
type runner func(cmdName string) (*bytes.Buffer, error)
|
||||
|
||||
// Varnish is used to store configuration values
|
||||
type Varnish struct {
|
||||
Stats []string
|
||||
Binary string
|
||||
|
||||
filter glob.Glob
|
||||
run runner
|
||||
}
|
||||
|
||||
var defaultStats = []string{"MAIN.cache_hit", "MAIN.cache_miss", "MAIN.uptime"}
|
||||
var defaultBinary = "/usr/bin/varnishstat"
|
||||
|
||||
var varnishSampleConfig = `
|
||||
var sampleConfig = `
|
||||
## The default location of the varnishstat binary can be overridden with:
|
||||
binary = "/usr/bin/varnishstat"
|
||||
|
||||
## By default, telegraf gather stats for 3 metric points.
|
||||
## Setting stats will override the defaults shown below.
|
||||
## stats may also be set to ["all"], which will collect all stats
|
||||
## Glob matching can be used, ie, stats = ["MAIN.*"]
|
||||
## stats may also be set to ["*"], which will collect all stats
|
||||
stats = ["MAIN.cache_hit", "MAIN.cache_miss", "MAIN.uptime"]
|
||||
`
|
||||
|
||||
@@ -46,44 +50,11 @@ func (s *Varnish) Description() string {
|
||||
|
||||
// SampleConfig displays configuration instructions
|
||||
func (s *Varnish) SampleConfig() string {
|
||||
return fmt.Sprintf(varnishSampleConfig, strings.Join(defaultStats, "\",\""))
|
||||
}
|
||||
|
||||
func (s *Varnish) setDefaults() {
|
||||
if len(s.Stats) == 0 {
|
||||
s.Stats = defaultStats
|
||||
}
|
||||
|
||||
if s.Binary == "" {
|
||||
s.Binary = defaultBinary
|
||||
}
|
||||
}
|
||||
|
||||
// Builds a filter function that will indicate whether a given stat should
|
||||
// be reported
|
||||
func (s *Varnish) statsFilter() func(string) bool {
|
||||
s.setDefaults()
|
||||
|
||||
// Build a set for constant-time lookup of whether stats should be included
|
||||
filter := make(map[string]struct{})
|
||||
for _, s := range s.Stats {
|
||||
filter[s] = struct{}{}
|
||||
}
|
||||
|
||||
// Create a function that respects the kwAll by always returning true
|
||||
// if it is set
|
||||
return func(stat string) bool {
|
||||
if s.Stats[0] == kwAll {
|
||||
return true
|
||||
}
|
||||
|
||||
_, found := filter[stat]
|
||||
return found
|
||||
}
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
// Shell out to varnish_stat and return the output
|
||||
var varnishStat = func(cmdName string) (*bytes.Buffer, error) {
|
||||
func varnishRunner(cmdName string) (*bytes.Buffer, error) {
|
||||
cmdArgs := []string{"-1"}
|
||||
|
||||
cmd := exec.Command(cmdName, cmdArgs...)
|
||||
@@ -104,13 +75,27 @@ var varnishStat = func(cmdName string) (*bytes.Buffer, error) {
|
||||
// 'section' tag and all stats that share that prefix will be reported as fields
|
||||
// with that tag
|
||||
func (s *Varnish) Gather(acc telegraf.Accumulator) error {
|
||||
s.setDefaults()
|
||||
out, err := varnishStat(s.Binary)
|
||||
if s.filter == nil {
|
||||
var err error
|
||||
if len(s.Stats) == 0 {
|
||||
s.filter, err = internal.CompileFilter(defaultStats)
|
||||
} else {
|
||||
// legacy support, change "all" -> "*":
|
||||
if s.Stats[0] == "all" {
|
||||
s.Stats[0] = "*"
|
||||
}
|
||||
s.filter, err = internal.CompileFilter(s.Stats)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
out, err := s.run(s.Binary)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error gathering metrics: %s", err)
|
||||
}
|
||||
|
||||
statsFilter := s.statsFilter()
|
||||
sectionMap := make(map[string]map[string]interface{})
|
||||
scanner := bufio.NewScanner(out)
|
||||
for scanner.Scan() {
|
||||
@@ -125,7 +110,7 @@ func (s *Varnish) Gather(acc telegraf.Accumulator) error {
|
||||
stat := cols[0]
|
||||
value := cols[1]
|
||||
|
||||
if !statsFilter(stat) {
|
||||
if s.filter != nil && !s.filter.Match(stat) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -138,7 +123,7 @@ func (s *Varnish) Gather(acc telegraf.Accumulator) error {
|
||||
sectionMap[section] = make(map[string]interface{})
|
||||
}
|
||||
|
||||
sectionMap[section][field], err = strconv.Atoi(value)
|
||||
sectionMap[section][field], err = strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Expected a numeric value for %s = %v\n",
|
||||
stat, value)
|
||||
@@ -160,5 +145,9 @@ func (s *Varnish) Gather(acc telegraf.Accumulator) error {
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("varnish", func() telegraf.Input { return &Varnish{} })
|
||||
inputs.Add("varnish", func() telegraf.Input {
|
||||
return &Varnish{
|
||||
run: varnishRunner,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -17,38 +17,12 @@ func fakeVarnishStat(output string) func(string) (*bytes.Buffer, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigsUsed(t *testing.T) {
|
||||
saved := varnishStat
|
||||
defer func() {
|
||||
varnishStat = saved
|
||||
}()
|
||||
|
||||
expecations := map[string]string{
|
||||
"": defaultBinary,
|
||||
"/foo/bar/baz": "/foo/bar/baz",
|
||||
}
|
||||
|
||||
for in, expected := range expecations {
|
||||
varnishStat = func(actual string) (*bytes.Buffer, error) {
|
||||
assert.Equal(t, expected, actual)
|
||||
return &bytes.Buffer{}, nil
|
||||
}
|
||||
|
||||
acc := &testutil.Accumulator{}
|
||||
v := &Varnish{Binary: in}
|
||||
v.Gather(acc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGather(t *testing.T) {
|
||||
saved := varnishStat
|
||||
defer func() {
|
||||
varnishStat = saved
|
||||
}()
|
||||
varnishStat = fakeVarnishStat(smOutput)
|
||||
|
||||
acc := &testutil.Accumulator{}
|
||||
v := &Varnish{Stats: []string{"all"}}
|
||||
v := &Varnish{
|
||||
run: fakeVarnishStat(smOutput),
|
||||
Stats: []string{"*"},
|
||||
}
|
||||
v.Gather(acc)
|
||||
|
||||
acc.HasMeasurement("varnish")
|
||||
@@ -60,14 +34,11 @@ func TestGather(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseFullOutput(t *testing.T) {
|
||||
saved := varnishStat
|
||||
defer func() {
|
||||
varnishStat = saved
|
||||
}()
|
||||
varnishStat = fakeVarnishStat(fullOutput)
|
||||
|
||||
acc := &testutil.Accumulator{}
|
||||
v := &Varnish{Stats: []string{"all"}}
|
||||
v := &Varnish{
|
||||
run: fakeVarnishStat(fullOutput),
|
||||
Stats: []string{"*"},
|
||||
}
|
||||
err := v.Gather(acc)
|
||||
|
||||
assert.NoError(t, err)
|
||||
@@ -77,15 +48,24 @@ func TestParseFullOutput(t *testing.T) {
|
||||
assert.Equal(t, 293, len(flat))
|
||||
}
|
||||
|
||||
func TestFieldConfig(t *testing.T) {
|
||||
saved := varnishStat
|
||||
defer func() {
|
||||
varnishStat = saved
|
||||
}()
|
||||
varnishStat = fakeVarnishStat(fullOutput)
|
||||
func TestFilterSomeStats(t *testing.T) {
|
||||
acc := &testutil.Accumulator{}
|
||||
v := &Varnish{
|
||||
run: fakeVarnishStat(fullOutput),
|
||||
Stats: []string{"MGT.*", "VBE.*"},
|
||||
}
|
||||
err := v.Gather(acc)
|
||||
|
||||
assert.NoError(t, err)
|
||||
acc.HasMeasurement("varnish")
|
||||
flat := flatten(acc.Metrics)
|
||||
assert.Len(t, acc.Metrics, 2)
|
||||
assert.Equal(t, 16, len(flat))
|
||||
}
|
||||
|
||||
func TestFieldConfig(t *testing.T) {
|
||||
expect := map[string]int{
|
||||
"all": 293,
|
||||
"*": 293,
|
||||
"": 0, // default
|
||||
"MAIN.uptime": 1,
|
||||
"MEMPOOL.req0.sz_needed,MAIN.fetch_bad": 2,
|
||||
@@ -93,7 +73,10 @@ func TestFieldConfig(t *testing.T) {
|
||||
|
||||
for fieldCfg, expected := range expect {
|
||||
acc := &testutil.Accumulator{}
|
||||
v := &Varnish{Stats: strings.Split(fieldCfg, ",")}
|
||||
v := &Varnish{
|
||||
run: fakeVarnishStat(fullOutput),
|
||||
Stats: strings.Split(fieldCfg, ","),
|
||||
}
|
||||
err := v.Gather(acc)
|
||||
|
||||
assert.NoError(t, err)
|
||||
@@ -130,18 +113,18 @@ MEMPOOL.vbc.sz_wanted 88 . Size requested
|
||||
|
||||
var parsedSmOutput = map[string]map[string]interface{}{
|
||||
"MAIN": map[string]interface{}{
|
||||
"uptime": 895,
|
||||
"cache_hit": 95,
|
||||
"cache_miss": 5,
|
||||
"uptime": uint64(895),
|
||||
"cache_hit": uint64(95),
|
||||
"cache_miss": uint64(5),
|
||||
},
|
||||
"MGT": map[string]interface{}{
|
||||
"uptime": 896,
|
||||
"child_start": 1,
|
||||
"uptime": uint64(896),
|
||||
"child_start": uint64(1),
|
||||
},
|
||||
"MEMPOOL": map[string]interface{}{
|
||||
"vbc.live": 0,
|
||||
"vbc.pool": 10,
|
||||
"vbc.sz_wanted": 88,
|
||||
"vbc.live": uint64(0),
|
||||
"vbc.pool": uint64(10),
|
||||
"vbc.sz_wanted": uint64(88),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user