Alerting/Annotations: Prevent panics from composite store jobs from crashing Grafana (#83459)

* Don't directly use pointer to json

* Don't crash entire process if a store job panics

* Add debug logs when failing to parse/handle Loki entries
This commit is contained in:
William Wernert
2024-02-28 13:16:37 -05:00
committed by GitHub
parent 9190fb28e8
commit af528d2f66
7 changed files with 116 additions and 9 deletions
@@ -69,6 +69,10 @@ func NewLokiHistorianStore(cfg setting.UnifiedAlertingStateHistorySettings, ft f
}
}
func (r *LokiHistorianStore) Type() string {
return "loki"
}
func (r *LokiHistorianStore) Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
if query.Type == "annotation" {
return make([]*annotations.ItemDTO, 0), nil
@@ -124,6 +128,7 @@ func (r *LokiHistorianStore) annotationsFromStream(stream historian.Stream, ac a
err := json.Unmarshal([]byte(sample.V), &entry)
if err != nil {
// bad data, skip
r.log.Debug("failed to unmarshal loki entry", "error", err, "entry", sample.V)
continue
}
@@ -135,6 +140,7 @@ func (r *LokiHistorianStore) annotationsFromStream(stream historian.Stream, ac a
transition, err := buildTransition(entry)
if err != nil {
// bad data, skip
r.log.Debug("failed to build transition", "error", err, "entry", entry)
continue
}
@@ -207,6 +213,10 @@ type number interface {
// numericMap converts a simplejson map[string]any to a map[string]N, where N is numeric (int or float).
func numericMap[N number](j *simplejson.Json) (map[string]N, error) {
if j == nil {
return nil, fmt.Errorf("unexpected nil value")
}
m, err := j.Map()
if err != nil {
return nil, err
@@ -374,7 +374,23 @@ func TestHasAccess(t *testing.T) {
})
}
func TestFloat64Map(t *testing.T) {
func TestNumericMap(t *testing.T) {
t.Run("should return error for nil value", func(t *testing.T) {
var jsonMap *simplejson.Json
_, err := numericMap[float64](jsonMap)
require.Error(t, err)
require.Contains(t, err.Error(), "unexpected nil value")
})
t.Run("should return error for nil interface value", func(t *testing.T) {
jsonMap := simplejson.NewFromAny(map[string]any{
"key1": nil,
})
_, err := numericMap[float64](jsonMap)
require.Error(t, err)
require.Contains(t, err.Error(), "unexpected value type")
})
t.Run(`should convert json string:float kv to Golang map[string]float64`, func(t *testing.T) {
jsonMap := simplejson.NewFromAny(map[string]any{
"key1": json.Number("1.0"),