From d2245ca0438e5792e8dec8beb3c74546a801969c Mon Sep 17 00:00:00 2001 From: Konstantin Nikitin Date: Mon, 28 Sep 2015 01:34:11 +0300 Subject: [PATCH] Fetching Statistics from memcached server --- memcache/memcache.go | 82 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/memcache/memcache.go b/memcache/memcache.go index 6eed4fbe..523495c2 100644 --- a/memcache/memcache.go +++ b/memcache/memcache.go @@ -110,6 +110,12 @@ var ( resultTouched = []byte("TOUCHED\r\n") resultClientErrorPrefix = []byte("CLIENT_ERROR ") + + statsGetHits = []byte("STAT get_hits ") + statsGetMisses = []byte("STAT get_misses ") + statsBytesWritten = []byte("STAT bytes_written ") + statsItems = []byte("STAT curr_items ") + statsBytes = []byte("STAT bytes ") ) // New returns a memcache client using the provided server(s) @@ -171,6 +177,24 @@ type conn struct { c *Client } +// Statistics is a record of memcached usage stats. +type Statistics struct { + // Counter of cache hits. + Hits uint64 + + // Counter of cache misses. + Misses uint64 + + // Counter of bytes transferred for gets. + ByteHits uint64 + + // Items currently in the cache. + Items uint64 + + // Size of all items currently in the cache. + Bytes uint64 +} + // release returns this connection back to the client's free pool func (cn *conn) release() { cn.c.putFreeConn(cn.addr, cn) @@ -667,3 +691,61 @@ func (c *Client) incrDecr(verb, key string, delta uint64) (uint64, error) { }) return val, err } + +func parseStatsLine(s []byte, expectedPrefix []byte) (uint64, error) { + if !bytes.HasPrefix(s, expectedPrefix) { + return 0, errors.New("line does not start with exceptedPrefix") + } + return strconv.ParseUint( + string(s[len(expectedPrefix):len(s)-2]), 10, 64) +} + +func parseStatsResponse(r *bufio.Reader, stats *Statistics) error { + for { + line, err := r.ReadSlice('\n') + if err != nil { + return err + } + if bytes.Equal(line, resultEnd) { + return nil + } + if hits, err := parseStatsLine(line, statsGetHits); err == nil { + stats.Hits = hits + continue + } + if misses, err := parseStatsLine(line, statsGetMisses); err == nil { + stats.Misses = misses + continue + } + if bytesWritten, err := parseStatsLine(line, statsBytesWritten); err == nil { + stats.ByteHits = bytesWritten + continue + } + if items, err := parseStatsLine(line, statsItems); err == nil { + stats.Items = items + continue + } + if bytes_total, err := parseStatsLine(line, statsBytes); err == nil { + stats.Bytes = bytes_total + continue + } + } +} + + +func (c *Client) Stats(addr net.Addr) (*Statistics, error) { + stats := new(Statistics) + err := c.withAddrRw(addr, func(rw *bufio.ReadWriter) error { + if _, err := fmt.Fprintf(rw, "stats\r\n"); err != nil { + return err + } + if err := rw.Flush(); err != nil { + return err + } + if err := parseStatsResponse(rw.Reader, stats); err != nil { + return err + } + return nil + }) + return stats, err +}