diff --git a/redis_exporter.go b/redis_exporter.go index 7402c2da..f1d57bdb 100644 --- a/redis_exporter.go +++ b/redis_exporter.go @@ -2,7 +2,7 @@ package main import ( "flag" - // "fmt" + "fmt" "log" "net/http" "os" @@ -162,7 +162,7 @@ func includeMetric(name string) bool { return ok } -func extractMetrics(info, addr string, scrapes chan<- scrapeResult) error { +func extractInfoMetrics(info, addr string, scrapes chan<- scrapeResult) error { lines := strings.Split(info, "\r\n") @@ -183,14 +183,14 @@ func extractMetrics(info, addr string, scrapes chan<- scrapeResult) error { stats := split[1] split := strings.Split(stats, ",") if len(split) != 3 { - log.Printf("wtf stats: %s", stats) + log.Printf("unexpected db stats format: %s", stats) continue } extract := func(s string) (val float64) { split := strings.Split(s, "=") if len(split) != 2 { - log.Printf("couldn't split %s", s) + log.Printf("unexpected db stats format: %s", s) return 0 } val, err := strconv.ParseFloat(split[1], 64) @@ -214,7 +214,23 @@ func extractMetrics(info, addr string, scrapes chan<- scrapeResult) error { } scrapes <- scrapeResult{Name: split[0], Addr: addr, Value: val} } + return nil +} + +func extractConfigMetrics(config []string, addr string, scrapes chan<- scrapeResult) error { + + if len(config)%2 != 0 { + return fmt.Errorf("invalid config: %#v", config) + } + for pos := 0; pos < len(config)/2; pos++ { + val, err := strconv.ParseFloat(config[pos*2+1], 64) + if err != nil { + log.Printf("couldn't parse %s, err: %s", config[pos*2+1], err) + continue + } + scrapes <- scrapeResult{Name: fmt.Sprintf("config_%s", config[pos*2]), Addr: addr, Value: val} + } return nil } @@ -224,10 +240,8 @@ func (e *Exporter) scrape(scrapes chan<- scrapeResult) { now := time.Now().UnixNano() e.totalScrapes.Inc() - //var err error errorCount := 0 for _, addr := range e.redis.addrs { - // log.Printf("opening connection to redis node %s", addr) c, err := redis.Dial("tcp", addr) if err != nil { log.Printf("redis err: %s", err) @@ -242,18 +256,26 @@ func (e *Exporter) scrape(scrapes chan<- scrapeResult) { } } info, err := redis.String(c.Do("INFO")) - c.Close() + if err == nil { + err = extractInfoMetrics(info, addr, scrapes) + } if err != nil { log.Printf("redis err: %s", err) errorCount++ - continue } - if err := extractMetrics(info, addr, scrapes); err != nil { + + config, err := redis.Strings(c.Do("CONFIG", "GET", "maxmemory")) + if err == nil { + err = extractConfigMetrics(config, addr, scrapes) + } + if err != nil { log.Printf("redis err: %s", err) errorCount++ } + + c.Close() } - // log.Printf("redis errors: %d err: %s", errorCount, err) + e.scrapeErrors.Set(float64(errorCount)) e.duration.Set(float64(time.Now().UnixNano()-now) / 1000000000) } @@ -296,12 +318,12 @@ func main() { http.Handle(*metricPath, prometheus.Handler()) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(` - Redis exporter - -

Redis exporter

-

Metrics

- - +Redis exporter + +

Redis exporter

+

Metrics

+ + `)) }) diff --git a/redis_exporter_test.go b/redis_exporter_test.go index 75c64939..3777be2c 100644 --- a/redis_exporter_test.go +++ b/redis_exporter_test.go @@ -1,13 +1,18 @@ package main /* + to run the tests with redis running on anything but localhost:6379 use + $ go test --redis.addr=: + for html coverage report run - go test -coverprofile=coverage.out && go tool cover -html=coverage.out + $ go test -coverprofile=coverage.out && go tool cover -html=coverage.out */ import ( + "flag" "fmt" "log" + "strings" "testing" "time" @@ -17,11 +22,12 @@ import ( var ( keys = []string{} ts = int32(time.Now().Unix()) + r = RedisHost{} ) func addKeysToDB(t *testing.T, db string) error { - c, err := redis.Dial("tcp", addrs[0]) + c, err := redis.Dial("tcp", r.addrs[0]) if err != nil { t.Errorf("couldn't setup redis, err: %s ", err) return err @@ -47,7 +53,7 @@ func addKeysToDB(t *testing.T, db string) error { func deleteKeysFromDB(t *testing.T, db string) error { - c, err := redis.Dial("tcp", addrs[0]) + c, err := redis.Dial("tcp", r.addrs[0]) if err != nil { log.Printf("redis err: %s", err) t.Errorf("couldn't setup redis, err: %s ", err) @@ -71,7 +77,7 @@ func deleteKeysFromDB(t *testing.T, db string) error { func TestCountingKeys(t *testing.T) { - e := NewRedisExporter(RedisHost{addrs: addrs}, "test") + e := NewRedisExporter(r, "test") scrapes := make(chan scrapeResult) go e.scrape(scrapes) @@ -118,7 +124,7 @@ func TestCountingKeys(t *testing.T) { func TestExporter(t *testing.T) { - e := NewRedisExporter(RedisHost{addrs: addrs}, "test") + e := NewRedisExporter(r, "test") scrapes := make(chan scrapeResult) go e.scrape(scrapes) @@ -143,9 +149,15 @@ func TestExporter(t *testing.T) { } func init() { - for _, n := range []string{"john", "paul", "ringo", "george"} { key := fmt.Sprintf("key-%s-%d", n, ts) keys = append(keys, key) } + + flag.Parse() + addrs := strings.Split(*redisAddr, ",") + if len(addrs) == 0 || len(addrs[0]) == 0 { + log.Fatal("Invalid parameter --redis.addr") + } + r = RedisHost{addrs: addrs} }