func (d *dataAccess) GetUnknownAndUnevalAlertKeys(alert string) ([]models.AlertKey, []models.AlertKey, error) { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "GetUnknownAndUnevalAlertKeys"})() conn := d.GetConnection() defer conn.Close() unknownS, err := redis.Strings(conn.Do("SMEMBERS", statesUnknownKey(alert))) if err != nil { return nil, nil, slog.Wrap(err) } unknown := make([]models.AlertKey, len(unknownS)) for i, u := range unknownS { unknown[i] = models.AlertKey(u) } unEvals, err := redis.Strings(conn.Do("SMEMBERS", statesUnevalKey(alert))) if err != nil { return nil, nil, slog.Wrap(err) } unevals := make([]models.AlertKey, len(unEvals)) for i, u := range unEvals { unevals[i] = models.AlertKey(u) } return unknown, unevals, nil }
func (d *dataAccess) GetFullErrorHistory() (map[string][]*models.AlertError, error) { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "GetFullErrorHistory"})() conn := d.GetConnection() defer conn.Close() alerts, err := redis.Strings(conn.Do("SMEMBERS", alertsWithErrors)) if err != nil { return nil, err } results := make(map[string][]*models.AlertError, len(alerts)) for _, a := range alerts { rows, err := redis.Strings(conn.Do("LRANGE", errorListKey(a), 0, -1)) if err != nil { return nil, err } list := make([]*models.AlertError, len(rows)) for i, row := range rows { ae := &models.AlertError{} err = json.Unmarshal([]byte(row), ae) if err != nil { return nil, err } list[i] = ae } results[a] = list } return results, nil }
func (d *dataAccess) GetTagMetadata(tags opentsdb.TagSet, name string) ([]*TagMetadata, error) { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "GetTagMeta"})() conn := d.GetConnection() defer conn.Close() args := []interface{}{} for tagK, tagV := range tags { args = append(args, tagMetaIdxKey(tagK, tagV)) } keys, err := redis.Strings(conn.Do("SINTER", args...)) if err != nil { return nil, err } args = []interface{}{} for _, key := range keys { if name == "" || strings.HasSuffix(key, ":"+name) { args = append(args, key) } } results, err := redis.Strings(conn.Do("MGET", args...)) data := []*TagMetadata{} for i := range args { // break up key to get tags and name key := args[i].(string)[len("tmeta:"):] sepIdx := strings.LastIndex(key, ":") tags := key[:sepIdx] name := key[sepIdx+1:] tagSet, err := opentsdb.ParseTags(tags) if err != nil { return nil, err } // break up response to get time and value parts := strings.SplitN(results[i], ":", 2) if len(parts) != 2 { return nil, fmt.Errorf("Expect metadata value to be `time:value`") } val := parts[1] time, err := strconv.ParseInt(parts[0], 10, 64) if err != nil { return nil, err } obj := &TagMetadata{ Tags: tagSet, Name: name, Value: val, LastTouched: time, } data = append(data, obj) } return data, nil }
func (d *dataAccess) GetActiveSilences() ([]*models.Silence, error) { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "GetActiveSilences"})() conn := d.GetConnection() defer conn.Close() now := time.Now().UTC() vals, err := redis.Strings(conn.Do("ZRANGEBYSCORE", silenceIdx, now.Unix(), "+inf")) if err != nil { return nil, err } if len(vals) == 0 { return nil, nil } silences, err := getSilences(vals, conn) if err != nil { return nil, err } filtered := make([]*models.Silence, 0, len(silences)) for _, s := range silences { if s.Start.After(now) { continue } filtered = append(filtered, s) } return filtered, nil }
func (d *dataAccess) GetIncidentsStartingInRange(start, end time.Time) ([]*models.Incident, error) { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "GetIncidentsStartingInRange"})() conn := d.GetConnection() defer conn.Close() ids, err := redis.Ints(conn.Do("ZRANGEBYSCORE", "incidentsByStart", start.UTC().Unix(), end.UTC().Unix())) if err != nil { return nil, err } args := make([]interface{}, len(ids)+1) args[0] = "incidents" for i := range ids { args[i+1] = ids[i] } jsons, err := redis.Strings(conn.Do("HMGET", args...)) if err != nil { return nil, err } incidents := make([]*models.Incident, len(jsons)) for i := range jsons { inc := &models.Incident{} if err = json.Unmarshal([]byte(jsons[i]), inc); err != nil { return nil, err } incidents[i] = inc } return incidents, nil }
//Things could forseeably get a bit inconsistent if concurrent changes happen in just the wrong way. //Clear all should do a more thourogh cleanup to fully reset things. func (d *dataAccess) ClearAll() error { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "ClearAll"})() conn := d.GetConnection() defer conn.Close() alerts, err := redis.Strings(conn.Do("SMEMBERS", alertsWithErrors)) if err != nil { return err } for _, a := range alerts { if _, err := conn.Do(d.LCLEAR(), errorListKey(a)); err != nil { return err } } if _, err := conn.Do(d.SCLEAR(), alertsWithErrors); err != nil { return err } if _, err := conn.Do(d.SCLEAR(), failingAlerts); err != nil { return err } if _, err = conn.Do(d.LCLEAR(), errorEvents); err != nil { return err } return nil }
func stringInt64Map(d interface{}, err error) (map[string]int64, error) { vals, err := redis.Strings(d, err) if err != nil { return nil, err } result := make(map[string]int64) for i := 1; i < len(vals); i += 2 { time, _ := strconv.ParseInt(vals[i], 10, 64) result[vals[i-1]] = time } return result, err }
func (d *dataAccess) GetFailingAlerts() (map[string]bool, error) { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "GetFailingAlertCounts"})() conn := d.GetConnection() defer conn.Close() alerts, err := redis.Strings(conn.Do("SMEMBERS", failingAlerts)) if err != nil { return nil, err } r := make(map[string]bool, len(alerts)) for _, a := range alerts { r[a] = true } return r, nil }
func (d *dataAccess) GetUntouchedSince(alert string, time int64) ([]models.AlertKey, error) { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "GetUntouchedSince"})() conn := d.GetConnection() defer conn.Close() results, err := redis.Strings(conn.Do("ZRANGEBYSCORE", statesLastTouchedKey(alert), "-inf", time)) if err != nil { return nil, slog.Wrap(err) } aks := make([]models.AlertKey, len(results)) for i := range results { aks[i] = models.AlertKey(results[i]) } return aks, nil }
func getSilences(ids []string, conn redis.Conn) ([]*models.Silence, error) { args := make([]interface{}, len(ids)+1) args[0] = silenceHash for i := range ids { args[i+1] = ids[i] } jsons, err := redis.Strings(conn.Do("HMGET", args...)) if err != nil { log.Fatal(err, args) return nil, err } silences := make([]*models.Silence, 0, len(jsons)) for _, j := range jsons { s := &models.Silence{} if err := json.Unmarshal([]byte(j), s); err != nil { return nil, err } silences = append(silences, s) } return silences, nil }
func (d *dataAccess) ClearNotifications(ak models.AlertKey) error { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "ClearNotifications"})() conn := d.GetConnection() defer conn.Close() nots, err := redis.Strings(conn.Do("SMEMBERS", notsByAlertKeyKey(ak))) if err != nil { return slog.Wrap(err) } if len(nots) == 0 { return nil } args := []interface{}{pendingNotificationsKey} for _, not := range nots { key := fmt.Sprintf("%s:%s", ak, not) args = append(args, key) } _, err = conn.Do("ZREM", args...) return slog.Wrap(err) }
func (d *dataAccess) ListSilences(endingAfter int64) (map[string]*models.Silence, error) { defer collect.StartTimer("redis", opentsdb.TagSet{"op": "ListSilences"})() conn := d.GetConnection() defer conn.Close() ids, err := redis.Strings(conn.Do("ZRANGEBYSCORE", silenceIdx, endingAfter, "+inf")) if err != nil { return nil, err } if len(ids) == 0 { return map[string]*models.Silence{}, nil } silences, err := getSilences(ids, conn) if err != nil { return nil, err } m := make(map[string]*models.Silence, len(silences)) for _, s := range silences { m[s.ID()] = s } return m, nil }
// zpop pops a value from the ZSET key using WATCH/MULTI/EXEC commands. func zpop(c redis.Conn, key string) (result string, err error) { defer func() { // Return connection to normal state on error. if err != nil { c.Do("DISCARD") } }() // Loop until transaction is successful. for { if _, err := c.Do("WATCH", key); err != nil { return "", err } members, err := redis.Strings(c.Do("ZRANGE", key, 0, 0)) if err != nil { return "", err } if len(members) != 1 { return "", redis.ErrNil } c.Send("MULTI") c.Send("ZREM", key, members[0]) queued, err := c.Do("EXEC") if err != nil { return "", err } if queued != nil { result = members[0] break } } return result, nil }
func (d *dataAccess) incidentMultiGet(conn redis.Conn, ids []int64) ([]*models.IncidentState, error) { if len(ids) == 0 { return nil, nil } // get all incident json keys args := make([]interface{}, 0, len(ids)) for _, id := range ids { args = append(args, incidentStateKey(id)) } jsons, err := redis.Strings(conn.Do("MGET", args...)) if err != nil { return nil, slog.Wrap(err) } results := make([]*models.IncidentState, 0, len(jsons)) for _, j := range jsons { state := &models.IncidentState{} if err = json.Unmarshal([]byte(j), state); err != nil { return nil, slog.Wrap(err) } results = append(results, state) } return results, nil }
actual valueError expected valueError }{ { "ints([v1, v2])", ve(redis.Ints([]interface{}{[]byte("4"), []byte("5")}, nil)), ve([]int{4, 5}, nil), }, { "ints(nil)", ve(redis.Ints(nil, nil)), ve([]int(nil), redis.ErrNil), }, { "strings([v1, v2])", ve(redis.Strings([]interface{}{[]byte("v1"), []byte("v2")}, nil)), ve([]string{"v1", "v2"}, nil), }, { "strings(nil)", ve(redis.Strings(nil, nil)), ve([]string(nil), redis.ErrNil), }, { "values([v1, v2])", ve(redis.Values([]interface{}{[]byte("v1"), []byte("v2")}, nil)), ve([]interface{}{[]byte("v1"), []byte("v2")}, nil), }, { "values(nil)", ve(redis.Values(nil, nil)),