func (api *Api) Call(name string, argv interface{}) interface{} { if arr, ok := argv.([]interface{}); ok { if n := len(arr); n > 0 { if m0, ok := arr[0].([]*Metrics); ok { for i := 1; i < n; i++ { if m, ok := arr[i].([]*Metrics); ok { for _, mi := range m { m0 = append(m0, mi) } } } switch strings.ToLower(name) { case "sum", "sumseries": return api.sumSeries(m0) case "div", "divseries", "divideseries": return api.divSeries(m0) case "diff", "diffseries": return api.diffSeries(m0) case "_": return m0 default: glog.Warningln("[ ! ]\tFunction not supported: ", name) } } } } return nil }
// Client tries to get first available client from pool, // otherwise creates new instance of client func Client() (*redis.Client, error) { for i := 0; i < len(clients); i++ { select { case c := <-clients: r := c.Cmd("PING") if r.Err != nil { glog.Warningln("PING error: ", r.Err) if err := c.Close(); err != nil { glog.Warningln("Close error: ", err) } continue } return c, nil case <-time.After(time.Duration(config.Cfg.DB.Timeout) * time.Second): glog.Warningln("DB Client timed out") } } return newClient() }
// Release pushes back client to pool (if number of available clients in the pool is < MaxClients), // otherwise closes client func Release(client *redis.Client) { if client != nil { if len(clients) < config.Cfg.DB.MaxClients { glog.Infoln("Releasing Db Client") clients <- client glog.Infoln("Number of idle Db Clients: ", len(clients)) } else { glog.Infoln("Closing Db Client") if err := client.Close(); err != nil { glog.Warningln("Close error: ", err) } } } }
/* * Get queries for metrics which matches to the key pattern (e.g.: status.*) * * [ * {"target": "status.200", "datapoints": [[1720.0, 1370846820], ...], }, * {"target": "status.204", "datapoints": [[1.0, 1370846820], ..., ]} * ] */ func Get(key string, from int64, to int64, maxDataPoints int) (ms []*Metrics) { var js []byte var data []map[string]interface{} if client, err := db.Client(); err != nil { glog.Errorln(err) } else { defer db.Release(client) if js, err = client.Cmd("EVALSHA", getSha, 1, key, from, to).Bytes(); err != nil { glog.Warningln(err) if js, err = client.Cmd("EVAL", config.Cfg.Metrics.GetScript, 1, key, from, to).Bytes(); err != nil { glog.Errorln(err) } } if err = json.Unmarshal(js, &data); err != nil { glog.Errorln(err) } } for _, d := range data { m := new(Metrics) m.Key = key if target, ok := d["target"].(string); ok { m.Target = target } datapoints, ok := d["datapoints"].([]interface{}) if !ok { datapoints = make([]interface{}, 0) } if config.Cfg.Metrics.ConsolidationStep < 1 || len(config.Cfg.Metrics.ConsolidationFunc) < 1 { for _, dp := range datapoints { if pt := makePt(dp); pt[1] != nil { m.Datapoints = append(m.Datapoints, pt) } } } else { step := consolidationStep(from, to, config.Cfg.Metrics.ConsolidationStep, maxDataPoints) m.Datapoints = consolidateBy(datapoints, from, to, step, config.Cfg.Metrics.ConsolidationFunc) } ms = append(ms, m) } return }
// GET: /render?target=my.key&from=-1h[&to=...&jsonp=...] func (h *RenderHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": glog.Infof("%v\n", r.URL) err := h.parseQuery(r) if err != nil { glog.Warningln(err) http.Error(w, err.Error(), http.StatusBadRequest) return } h.jsonResponse(w, api.Eval(h.target, h.from, h.to, &metrics.Api{h.maxDataPoints})) glog.Flush() default: http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) } }
func Add(key string, value string, timestamp int64) { if client, err := db.Client(); err != nil { glog.Errorln(err) } else { defer db.Release(client) if r := client.Cmd("EVALSHA", addSha, 1, key, value, timestamp); r.Err != nil { glog.Warningln(r.Err) if r = client.Cmd("EVAL", config.Cfg.Metrics.AddScript, 1, key, value, timestamp); r.Err != nil { glog.Errorln(r.Err) } } else { glog.Infof("[OK: %v]\t(%s %s)|%d", r, key, value, timestamp) } } }
func Ttl(from int64, to int64) { if client, err := db.Client(); err != nil { glog.Errorln(err) } else { t0 := time.Now() defer db.Release(client) if r := client.Cmd("EVALSHA", ttlSha, 1, "*", from, to); r.Err != nil { glog.Warningln(r.Err) if r = client.Cmd("EVAL", config.Cfg.Metrics.TtlScript, 1, "*", from, to); r.Err != nil { glog.Errorln(r.Err) } } else { t1 := time.Now() glog.Infof("ZREMRANGEBYSCORE(%d, %d): %v in %v", from, to, r, t1.Sub(t0)) } } }
// Handle TCP Connections func handle(conn net.Conn) { glog.Infof("Connection: %s -> %s\n", conn.RemoteAddr(), conn.LocalAddr()) defer func() { glog.Infof("Closing connection: %s\n", conn.RemoteAddr()) conn.Close() glog.Flush() }() scanner := bufio.NewScanner(conn) for scanner.Scan() { if m := strings.Split(scanner.Text(), " "); len(m) > 2 { if ts, err := strconv.ParseInt(m[2], 10, 0); err != nil { glog.Warningln(err) continue } else { metrics.Add(m[0], m[1], ts) } } } if err := scanner.Err(); err != nil { glog.Errorln(err) } }
func makePt(dp interface{}) (pt Pt) { if err := json.Unmarshal([]byte(dp.(string)), &pt); err != nil { glog.Warningln(err) } return }