forked from cortexproject/cortex
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutil.go
More file actions
121 lines (97 loc) · 3.5 KB
/
util.go
File metadata and controls
121 lines (97 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package queryapi
import (
"context"
"errors"
"fmt"
"net/http"
"time"
"github.com/gogo/status"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/util/annotations"
"github.com/weaveworks/common/httpgrpc"
"github.com/cortexproject/cortex/pkg/util"
)
var (
ErrEndBeforeStart = httpgrpc.Errorf(http.StatusBadRequest, "%s", "end timestamp must not be before start time")
ErrNegativeStep = httpgrpc.Errorf(http.StatusBadRequest, "%s", "zero or negative query resolution step widths are not accepted. Try a positive integer")
ErrStepTooSmall = httpgrpc.Errorf(http.StatusBadRequest, "%s", "exceeded maximum resolution of 11,000 points per timeseries. Try decreasing the query resolution (?step=XX)")
ErrUpstreamRequestTimeout = "upstream request timeout"
)
func extractQueryOpts(r *http.Request) (promql.QueryOpts, error) {
var duration time.Duration
if strDuration := r.FormValue("lookback_delta"); strDuration != "" {
parsedDuration, err := util.ParseDurationMs(strDuration)
if err != nil {
return nil, httpgrpc.Errorf(http.StatusBadRequest, "error parsing lookback delta duration: %v", err)
}
duration = convertMsToDuration(parsedDuration)
}
return promql.NewPrometheusQueryOpts(r.FormValue("stats") == "all", duration), nil
}
const (
statusSuccess = "success"
// Non-standard status code (originally introduced by nginx) for the case when a client closes
// the connection while the server is still processing the request.
statusClientClosedConnection = 499
)
type errorType string
const (
errorTimeout errorType = "timeout"
errorCanceled errorType = "canceled"
errorExec errorType = "execution"
errorBadData errorType = "bad_data"
errorInternal errorType = "internal"
errorNotAcceptable errorType = "not_acceptable"
)
type apiError struct {
typ errorType
err error
}
func (e *apiError) Error() string {
return fmt.Sprintf("%s: %s", e.typ, e.err)
}
func returnAPIError(err error) *apiError {
if err == nil {
return nil
}
var eqc promql.ErrQueryCanceled
var eqt promql.ErrQueryTimeout
var es promql.ErrStorage
switch {
case errors.As(err, &eqc):
return &apiError{errorCanceled, httpgrpc.Errorf(statusClientClosedConnection, "%v", err)}
case errors.As(err, &eqt):
return &apiError{errorTimeout, httpgrpc.Errorf(http.StatusServiceUnavailable, "%v", err)}
case errors.As(err, &es):
return &apiError{errorInternal, httpgrpc.Errorf(http.StatusInternalServerError, "%v", err)}
}
if errors.Is(err, context.Canceled) {
return &apiError{errorCanceled, httpgrpc.Errorf(statusClientClosedConnection, "%v", err)}
}
return &apiError{errorExec, httpgrpc.Errorf(http.StatusUnprocessableEntity, "%v", err)}
}
type apiFuncResult struct {
data any
err *apiError
warnings annotations.Annotations
finalizer func()
}
type apiFunc func(r *http.Request) apiFuncResult
func invalidParamError(err error, parameter string) apiFuncResult {
return apiFuncResult{nil, &apiError{
errorBadData, DecorateWithParamName(err, parameter),
}, nil, nil}
}
func convertMsToTime(unixMs int64) time.Time {
return time.Unix(0, unixMs*int64(time.Millisecond))
}
func convertMsToDuration(unixMs int64) time.Duration {
return time.Duration(unixMs) * time.Millisecond
}
func DecorateWithParamName(err error, field string) error {
errTmpl := "invalid parameter %q; %v"
if status, ok := status.FromError(err); ok {
return httpgrpc.Errorf(int(status.Code()), errTmpl, field, status.Message())
}
return fmt.Errorf(errTmpl, field, err)
}