cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.30.2

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/promapi/errors.go

109lines · modecode

1package promapi
2
3import (
4 "context"
5 "encoding/json"
6 "errors"
7 "fmt"
8 "net"
9 "net/http"
10 "syscall"
11
12 v1 "github.com/prometheus/client_golang/api/prometheus/v1"
13 "github.com/prymitive/current"
14)
15
16func IsUnavailableError(err error) bool {
17 var e1 APIError
18 if ok := errors.As(err, &e1); ok {
19 return e1.ErrorType == v1.ErrServer
20 }
21
22 return true
23}
24
25type APIError struct {
26 Status string `json:"status"`
27 ErrorType v1.ErrorType `json:"errorType"`
28 Err string `json:"error"`
29}
30
31func (e APIError) Error() string {
32 return e.Err
33}
34
35const (
36 ErrUnknown v1.ErrorType = "unknown"
37 ErrJSONStream v1.ErrorType = "json_stream"
38)
39
40func decodeErrorType(s string) v1.ErrorType {
41 switch s {
42 case string(v1.ErrBadData):
43 return v1.ErrBadData
44 case string(v1.ErrTimeout):
45 return v1.ErrTimeout
46 case string(v1.ErrCanceled):
47 return v1.ErrCanceled
48 case string(v1.ErrExec):
49 return v1.ErrExec
50 case string(v1.ErrBadResponse):
51 return v1.ErrBadResponse
52 case string(v1.ErrServer):
53 return v1.ErrServer
54 case string(v1.ErrClient):
55 return v1.ErrClient
56 default:
57 return ErrUnknown
58 }
59}
60
61func decodeError(err error) string {
62 if errors.Is(err, context.Canceled) {
63 return context.Canceled.Error()
64 }
65
66 if errors.Is(err, syscall.ECONNREFUSED) {
67 return "connection refused"
68 }
69
70 var neterr net.Error
71 if ok := errors.As(err, &neterr); ok && neterr.Timeout() {
72 return "connection timeout"
73 }
74
75 var e1 APIError
76 if ok := errors.As(err, &e1); ok {
77 return fmt.Sprintf("%s: %s", e1.ErrorType, e1.Err)
78 }
79
80 return err.Error()
81}
82
83func tryDecodingAPIError(resp *http.Response) error {
84 var status, errType, errText string
85 decoder := current.Object(
86 current.Key("status", current.Value(func(s string, isNil bool) {
87 status = s
88 })),
89 current.Key("error", current.Value(func(s string, isNil bool) {
90 errText = s
91 })),
92 current.Key("errorType", current.Value(func(s string, isNil bool) {
93 errType = s
94 })),
95 )
96
97 dec := json.NewDecoder(resp.Body)
98 if err := decoder.Stream(dec); err != nil {
99 switch resp.StatusCode / 100 {
100 case 4:
101 return APIError{Status: "error", ErrorType: v1.ErrClient, Err: fmt.Sprintf("client error: %d", resp.StatusCode)}
102 case 5:
103 return APIError{Status: "error", ErrorType: v1.ErrServer, Err: fmt.Sprintf("server error: %d", resp.StatusCode)}
104 }
105 return APIError{Status: "error", ErrorType: v1.ErrBadResponse, Err: fmt.Sprintf("bad response code: %d", resp.StatusCode)}
106 }
107
108 return APIError{Status: status, ErrorType: decodeErrorType(errType), Err: errText}
109}