cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.67.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/promapi/errors.go

133lines · modeblame

e6a0531fLukasz Mierzwa4 years ago1package promapi
2
3import (
4296ae4fLukasz Mierzwa4 years ago4"context"
2ea75469Lukasz Mierzwa3 years ago5"encoding/json"
e6a0531fLukasz Mierzwa4 years ago6"errors"
4296ae4fLukasz Mierzwa4 years ago7"fmt"
a795cccaLukasz Mierzwa2 years ago8"log/slog"
e6a0531fLukasz Mierzwa4 years ago9"net"
f393e060Lukasz Mierzwa3 years ago10"net/http"
552e44c1Lukasz Mierzwa3 years ago11"strings"
e6a0531fLukasz Mierzwa4 years ago12"syscall"
13
14v1 "github.com/prometheus/client_golang/api/prometheus/v1"
2ea75469Lukasz Mierzwa3 years ago15"github.com/prymitive/current"
e6a0531fLukasz Mierzwa4 years ago16)
17
18func IsUnavailableError(err error) bool {
f393e060Lukasz Mierzwa3 years ago19var e1 APIError
20if ok := errors.As(err, &e1); ok {
21return e1.ErrorType == v1.ErrServer
e6a0531fLukasz Mierzwa4 years ago22}
23return true
24}
25
552e44c1Lukasz Mierzwa3 years ago26func IsQueryTooExpensive(err error) bool {
27var e1 APIError
28if ok := errors.As(err, &e1); ok {
29if e1.ErrorType != v1.ErrExec {
30return false
31}
32if strings.HasPrefix(e1.Err, "query processing would load too many samples into memory in ") {
33return true
34}
35if strings.HasSuffix(e1.Err, "expanding series: context deadline exceeded") {
36return true
37}
38}
39return false
40}
41
0483c1c0Lukasz Mierzwa4 years ago42type APIError struct {
43Status string `json:"status"`
44ErrorType v1.ErrorType `json:"errorType"`
f393e060Lukasz Mierzwa3 years ago45Err string `json:"error"`
46}
47
48func (e APIError) Error() string {
49return e.Err
50}
51
52const (
53ErrUnknown v1.ErrorType = "unknown"
54ErrJSONStream v1.ErrorType = "json_stream"
55)
56
57func decodeErrorType(s string) v1.ErrorType {
58switch s {
59case string(v1.ErrBadData):
60return v1.ErrBadData
61case string(v1.ErrTimeout):
62return v1.ErrTimeout
63case string(v1.ErrCanceled):
64return v1.ErrCanceled
65case string(v1.ErrExec):
66return v1.ErrExec
67case string(v1.ErrBadResponse):
68return v1.ErrBadResponse
69case string(v1.ErrServer):
70return v1.ErrServer
71case string(v1.ErrClient):
72return v1.ErrClient
73default:
74return ErrUnknown
75}
0483c1c0Lukasz Mierzwa4 years ago76}
77
552e44c1Lukasz Mierzwa3 years ago78const (
79errConnRefused = "connection refused"
80errConnTimeout = "connection timeout"
81)
82
4296ae4fLukasz Mierzwa4 years ago83func decodeError(err error) string {
84if errors.Is(err, context.Canceled) {
85return context.Canceled.Error()
86}
87
e6a0531fLukasz Mierzwa4 years ago88if errors.Is(err, syscall.ECONNREFUSED) {
552e44c1Lukasz Mierzwa3 years ago89return errConnRefused
e6a0531fLukasz Mierzwa4 years ago90}
91
92var neterr net.Error
93if ok := errors.As(err, &neterr); ok && neterr.Timeout() {
552e44c1Lukasz Mierzwa3 years ago94return errConnTimeout
e6a0531fLukasz Mierzwa4 years ago95}
96
f393e060Lukasz Mierzwa3 years ago97var e1 APIError
98if ok := errors.As(err, &e1); ok {
99return fmt.Sprintf("%s: %s", e1.ErrorType, e1.Err)
e6a0531fLukasz Mierzwa4 years ago100}
101
4296ae4fLukasz Mierzwa4 years ago102return err.Error()
e6a0531fLukasz Mierzwa4 years ago103}
f393e060Lukasz Mierzwa3 years ago104
105func tryDecodingAPIError(resp *http.Response) error {
a795cccaLukasz Mierzwa2 years ago106slog.Debug("Trying to parse Prometheus error response", slog.Int("code", resp.StatusCode))
552e44c1Lukasz Mierzwa3 years ago107
2ea75469Lukasz Mierzwa3 years ago108var status, errType, errText string
109decoder := current.Object(
faf2c006Lukasz Mierzwa2 years ago110current.Key("status", current.Value(func(s string, _ bool) {
2ea75469Lukasz Mierzwa3 years ago111status = s
112})),
faf2c006Lukasz Mierzwa2 years ago113current.Key("error", current.Value(func(s string, _ bool) {
2ea75469Lukasz Mierzwa3 years ago114errText = s
115})),
faf2c006Lukasz Mierzwa2 years ago116current.Key("errorType", current.Value(func(s string, _ bool) {
2ea75469Lukasz Mierzwa3 years ago117errType = s
118})),
119)
120
121dec := json.NewDecoder(resp.Body)
122if err := decoder.Stream(dec); err != nil {
123switch resp.StatusCode / 100 {
124case 4:
125return APIError{Status: "error", ErrorType: v1.ErrClient, Err: fmt.Sprintf("client error: %d", resp.StatusCode)}
126case 5:
127return APIError{Status: "error", ErrorType: v1.ErrServer, Err: fmt.Sprintf("server error: %d", resp.StatusCode)}
128}
129return APIError{Status: "error", ErrorType: v1.ErrBadResponse, Err: fmt.Sprintf("bad response code: %d", resp.StatusCode)}
f393e060Lukasz Mierzwa3 years ago130}
131
2ea75469Lukasz Mierzwa3 years ago132return APIError{Status: status, ErrorType: decodeErrorType(errType), Err: errText}
f393e060Lukasz Mierzwa3 years ago133}