Skip to content

Commit

Permalink
Statsd: unit tests for gauges, sets, counters
Browse files Browse the repository at this point in the history
  • Loading branch information
sparrc committed Oct 6, 2015
1 parent 61d0e5c commit 1d7cde5
Show file tree
Hide file tree
Showing 3 changed files with 481 additions and 15 deletions.
2 changes: 1 addition & 1 deletion plugins/statsd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ implementation. In short, the telegraf statsd listener will accept:
- `users.unique:101|s`
- `users.unique:101|s`
- `users.unique:102|s` <- would result in a count of 2 for `users.unique`
- Timers
- Timings
- TODO
42 changes: 29 additions & 13 deletions plugins/statsd/statsd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package statsd

import (
"errors"
"log"
"net"
"strconv"
Expand Down Expand Up @@ -44,6 +45,20 @@ type Statsd struct {
}
}

func NewStatsd() *Statsd {
s := Statsd{}

// Make data structures
s.done = make(chan struct{})
s.in = make(chan string, s.AllowedPendingMessages)
s.inmetrics = make(chan metric, s.AllowedPendingMessages)
s.gauges = make(map[string]cachedmetric)
s.counters = make(map[string]cachedmetric)
s.sets = make(map[string]cachedmetric)

return &s
}

// One statsd metric, form is <bucket>:<value>|<mtype>|@<samplerate>
type metric struct {
name string
Expand Down Expand Up @@ -201,29 +216,29 @@ func (s *Statsd) parser() error {

// parseStatsdLine will parse the given statsd line, validating it as it goes.
// If the line is valid, it will be cached for the next call to Gather()
func (s *Statsd) parseStatsdLine(line string) {
func (s *Statsd) parseStatsdLine(line string) error {
s.Lock()
defer s.Unlock()

// Validate splitting the line on "|"
m := metric{}
parts1 := strings.Split(line, "|")
if len(parts1) < 2 {
log.Printf("Error splitting '|', Unable to parse metric: %s\n", line)
return
log.Printf("Error: splitting '|', Unable to parse metric: %s\n", line)
return errors.New("Error Parsing statsd line")
} else if len(parts1) > 2 {
sr := parts1[2]
errmsg := "Error: parsing sample rate, %s, it must be in format like: " +
"@0.1, @0.5, etc. Ignoring sample rate for line: %s\n"
if strings.Contains(sr, "@") && len(sr) > 1 {
samplerate, err := strconv.ParseFloat(sr[1:], 64)
if err != nil {
log.Printf("Error parsing sample rate: %s\n", err.Error())
log.Printf(errmsg, err.Error(), line)
} else {
m.samplerate = samplerate
}
} else {
msg := "Error parsing sample rate, it must be in format like: " +
"@0.1, @0.5, etc. Ignoring sample rate for line: %s\n"
log.Printf(msg, line)
log.Printf(errmsg, "", line)
}
}

Expand All @@ -232,30 +247,30 @@ func (s *Statsd) parseStatsdLine(line string) {
case "g", "c", "s", "ms", "h":
m.mtype = parts1[1]
default:
log.Printf("Statsd Metric type %s unsupported", parts1[1])
return
log.Printf("Error: Statsd Metric type %s unsupported", parts1[1])
return errors.New("Error Parsing statsd line")
}

// Validate splitting the rest of the line on ":"
parts2 := strings.Split(parts1[0], ":")
if len(parts2) != 2 {
log.Printf("Error splitting ':', Unable to parse metric: %s\n", line)
return
log.Printf("Error: splitting ':', Unable to parse metric: %s\n", line)
return errors.New("Error Parsing statsd line")
}
m.bucket = parts2[0]

// Parse the value
if strings.ContainsAny(parts2[1], "-+") {
if m.mtype != "g" {
log.Printf("Error: +- values are only supported for gauges: %s\n", line)
return
return errors.New("Error Parsing statsd line")
}
m.additive = true
}
v, err := strconv.ParseInt(parts2[1], 10, 64)
if err != nil {
log.Printf("Error: parsing value to int64: %s\n", line)
return
return errors.New("Error Parsing statsd line")
}
// If a sample rate is given with a counter, divide value by the rate
if m.samplerate != 0 && m.mtype == "c" {
Expand All @@ -278,6 +293,7 @@ func (s *Statsd) parseStatsdLine(line string) {
log.Printf(dropwarn, line)
}
}
return nil
}

// parseName parses the given bucket name with the list of bucket maps in the
Expand Down
Loading

0 comments on commit 1d7cde5

Please sign in to comment.