github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/ruler/base/error_translate_queryable.go (about) 1 package base 2 3 import ( 4 "context" 5 6 "github.com/gogo/status" 7 "github.com/pkg/errors" 8 "github.com/prometheus/prometheus/model/labels" 9 "github.com/prometheus/prometheus/promql" 10 "github.com/prometheus/prometheus/storage" 11 12 storage_errors "github.com/grafana/loki/pkg/storage/errors" 13 "github.com/grafana/loki/pkg/util/validation" 14 ) 15 16 // TranslateToPromqlAPIError converts error to one of promql.Errors for consumption in PromQL API. 17 // PromQL API only recognizes few errors, and converts everything else to HTTP status code 422. 18 // 19 // Specifically, it supports: 20 // 21 // promql.ErrQueryCanceled, mapped to 503 22 // promql.ErrQueryTimeout, mapped to 503 23 // promql.ErrStorage mapped to 500 24 // anything else is mapped to 422 25 // 26 // Querier code produces different kinds of errors, and we want to map them to above-mentioned HTTP status codes correctly. 27 // 28 // Details: 29 // - vendor/github.com/prometheus/prometheus/web/api/v1/api.go, respondError function only accepts *apiError types. 30 // - translation of error to *apiError happens in vendor/github.com/prometheus/prometheus/web/api/v1/api.go, returnAPIError method. 31 func TranslateToPromqlAPIError(err error) error { 32 if err == nil { 33 return err 34 } 35 36 switch errors.Cause(err).(type) { 37 case promql.ErrStorage, promql.ErrTooManySamples, promql.ErrQueryCanceled, promql.ErrQueryTimeout: 38 // Don't translate those, just in case we use them internally. 39 return err 40 case storage_errors.QueryError, validation.LimitError: 41 // This will be returned with status code 422 by Prometheus API. 42 return err 43 default: 44 if errors.Is(err, context.Canceled) { 45 return err // 422 46 } 47 48 s, ok := status.FromError(err) 49 50 if !ok { 51 s, ok = status.FromError(errors.Cause(err)) 52 } 53 54 if ok { 55 code := s.Code() 56 57 // Treat these as HTTP status codes, even though they are supposed to be grpc codes. 58 if code >= 400 && code < 500 { 59 // Return directly, will be mapped to 422 60 return err 61 } else if code >= 500 && code < 599 { 62 // Wrap into ErrStorage for mapping to 500 63 return promql.ErrStorage{Err: err} 64 } 65 } 66 67 // All other errors will be returned as 500. 68 return promql.ErrStorage{Err: err} 69 } 70 } 71 72 // ErrTranslateFn is used to translate or wrap error before returning it by functions in 73 // storage.SampleAndChunkQueryable interface. 74 // Input error may be nil. 75 type ErrTranslateFn func(err error) error 76 77 func NewErrorTranslateQueryableWithFn(q storage.Queryable, fn ErrTranslateFn) storage.Queryable { 78 return errorTranslateQueryable{q: q, fn: fn} 79 } 80 81 type errorTranslateQueryable struct { 82 q storage.Queryable 83 fn ErrTranslateFn 84 } 85 86 func (e errorTranslateQueryable) Querier(ctx context.Context, mint, maxt int64) (storage.Querier, error) { 87 q, err := e.q.Querier(ctx, mint, maxt) 88 return errorTranslateQuerier{q: q, fn: e.fn}, e.fn(err) 89 } 90 91 type errorTranslateQuerier struct { 92 q storage.Querier 93 fn ErrTranslateFn 94 } 95 96 func (e errorTranslateQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([]string, storage.Warnings, error) { 97 values, warnings, err := e.q.LabelValues(name, matchers...) 98 return values, warnings, e.fn(err) 99 } 100 101 func (e errorTranslateQuerier) LabelNames(matchers ...*labels.Matcher) ([]string, storage.Warnings, error) { 102 values, warnings, err := e.q.LabelNames(matchers...) 103 return values, warnings, e.fn(err) 104 } 105 106 func (e errorTranslateQuerier) Close() error { 107 return e.fn(e.q.Close()) 108 } 109 110 func (e errorTranslateQuerier) Select(sortSeries bool, hints *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet { 111 s := e.q.Select(sortSeries, hints, matchers...) 112 return errorTranslateSeriesSet{s: s, fn: e.fn} 113 } 114 115 type errorTranslateSeriesSet struct { 116 s storage.SeriesSet 117 fn ErrTranslateFn 118 } 119 120 func (e errorTranslateSeriesSet) Next() bool { 121 return e.s.Next() 122 } 123 124 func (e errorTranslateSeriesSet) At() storage.Series { 125 return e.s.At() 126 } 127 128 func (e errorTranslateSeriesSet) Err() error { 129 return e.fn(e.s.Err()) 130 } 131 132 func (e errorTranslateSeriesSet) Warnings() storage.Warnings { 133 return e.s.Warnings() 134 }