github.com/mackerelio/mackerel-agent-plugins@v0.89.3/mackerel-plugin-twemproxy/lib/stats.go (about) 1 package mptwemproxy 2 3 import ( 4 "bufio" 5 "encoding/json" 6 "fmt" 7 "net" 8 "time" 9 ) 10 11 // TwemproxyStats represents a twemproxy stats 12 type TwemproxyStats struct { 13 TotalConnections *uint64 14 CurrConnections *uint64 15 Pools map[string]*PoolStats 16 } 17 18 // PoolStats represents a pool stats 19 type PoolStats struct { 20 ClientEOF *uint64 21 ClientErr *uint64 22 ClientConnections *uint64 23 ServerEjects *uint64 24 ForwardError *uint64 25 Servers map[string]*ServerStats 26 } 27 28 // ServerStats represents a server stats 29 type ServerStats struct { 30 ServerEOF *uint64 31 ServerErr *uint64 32 ServerTimedout *uint64 33 ServerConnections *uint64 34 OutQueueBytes *uint64 35 InQueueBytes *uint64 36 OutQueue *uint64 37 InQueue *uint64 38 RequestBytes *uint64 39 ResponseBytes *uint64 40 Requests *uint64 41 Responses *uint64 42 } 43 44 func getStats(p TwemproxyPlugin) (*TwemproxyStats, error) { 45 // get json data 46 address := p.Address 47 timeout := time.Duration(p.Timeout) * time.Second 48 conn, err := net.DialTimeout("tcp", address, timeout) 49 if err != nil { 50 return nil, err 51 } 52 res := bufio.NewReader(conn) 53 54 // decode the json data to TwemproxyStats struct 55 var t TwemproxyStats 56 decoder := json.NewDecoder(res) 57 err = decoder.Decode(&t) 58 if err != nil { 59 return nil, err 60 } 61 return &t, nil 62 } 63 64 // UnmarshalJSON interface for json.Unmarshaler 65 func (t *TwemproxyStats) UnmarshalJSON(data []byte) error { 66 var raw map[string]interface{} 67 err := json.Unmarshal(data, &raw) 68 if err != nil { 69 return err 70 } 71 72 t.Pools = make(map[string]*PoolStats) 73 74 L: 75 for k, v := range raw { 76 switch v := v.(type) { 77 case float64: 78 cv := uint64(v) 79 switch k { 80 case "total_connections": 81 t.TotalConnections = &cv 82 case "curr_connections": 83 t.CurrConnections = &cv 84 case "uptime", "timestamp": 85 // do not use these parameters. skip. 86 default: 87 err = fmt.Errorf("invalid key: %v in rawTwemproxy: %v", k, raw) 88 break L 89 } 90 case map[string]interface{}: 91 pool, perr := decodePoolStats(v) 92 if perr != nil { 93 err = perr 94 break L 95 } 96 t.Pools[k] = pool 97 case string: 98 // do not use parameters(service, source, version). skip. 99 default: 100 err = fmt.Errorf("invalid type in rawTwemproxy: %v", raw) 101 break L 102 } 103 } 104 105 return err 106 } 107 108 func decodePoolStats(rawStats map[string]interface{}) (*PoolStats, error) { 109 pool := new(PoolStats) 110 pool.Servers = make(map[string]*ServerStats) 111 112 var err error 113 114 L: 115 for k, v := range rawStats { 116 switch v := v.(type) { 117 case float64: 118 cv := uint64(v) 119 switch k { 120 case "client_eof": 121 pool.ClientEOF = &cv 122 case "client_err": 123 pool.ClientErr = &cv 124 case "client_connections": 125 pool.ClientConnections = &cv 126 case "server_ejects": 127 pool.ServerEjects = &cv 128 case "forward_error": 129 pool.ForwardError = &cv 130 case "fragments": 131 // do not use this parameter. skip. 132 default: 133 err = fmt.Errorf("invalid key: %v in rawPool: %v", k, rawStats) 134 break L 135 } 136 case map[string]interface{}: 137 server, serr := decodeServerStats(v) 138 if serr != nil { 139 err = serr 140 break L 141 } 142 pool.Servers[k] = server 143 default: 144 err = fmt.Errorf("invalid type in rawPool: %v", rawStats) 145 break L 146 } 147 } 148 149 if err != nil { 150 return nil, err 151 } 152 return pool, nil 153 } 154 155 func decodeServerStats(rawStats map[string]interface{}) (*ServerStats, error) { 156 server := new(ServerStats) 157 158 var err error 159 160 L: 161 for k, v := range rawStats { 162 cv := uint64(v.(float64)) 163 switch k { 164 case "server_eof": 165 server.ServerEOF = &cv 166 case "server_err": 167 server.ServerErr = &cv 168 case "server_timedout": 169 server.ServerTimedout = &cv 170 case "server_connections": 171 server.ServerConnections = &cv 172 case "out_queue_bytes": 173 server.OutQueueBytes = &cv 174 case "in_queue_bytes": 175 server.InQueueBytes = &cv 176 case "out_queue": 177 server.OutQueue = &cv 178 case "in_queue": 179 server.InQueue = &cv 180 case "request_bytes": 181 server.RequestBytes = &cv 182 case "response_bytes": 183 server.ResponseBytes = &cv 184 case "requests": 185 server.Requests = &cv 186 case "responses": 187 server.Responses = &cv 188 case "server_ejected_at": 189 // do not use this parameter. skip. 190 default: 191 err = fmt.Errorf("invalid key: %v in rawServer: %v", k, rawStats) 192 break L 193 } 194 } 195 196 if err != nil { 197 return nil, err 198 } 199 return server, nil 200 }