-
Notifications
You must be signed in to change notification settings - Fork 403
/
error_response.go
80 lines (70 loc) · 2.53 KB
/
error_response.go
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
package server
import (
"context"
"encoding/json"
"errors"
"net/http"
"runtime/debug"
"github.com/fnproject/fn/api/common"
"github.com/fnproject/fn/api/models"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/status"
)
// ErrInternalServerError returned when something exceptional happens.
var ErrInternalServerError = errors.New("internal server error")
func simpleError(err error) *models.Error {
return &models.Error{Message: err.Error()}
}
func handleErrorResponse(c *gin.Context, err error) {
HandleErrorResponse(c.Request.Context(), c.Writer, err)
}
// HandleErrorResponse used to handle response errors in the same way.
func HandleErrorResponse(ctx context.Context, w http.ResponseWriter, err error) {
log := common.Logger(ctx)
if w, ok := err.(models.APIErrorWrapper); ok {
log = log.WithField("root_error", w.RootError())
}
if ctx.Err() == context.Canceled {
log.Info("client context cancelled")
w.WriteHeader(models.ErrClientCancel.Code())
return
}
var statuscode int
if e, ok := err.(models.APIError); ok {
if e.Code() >= 500 {
log.WithFields(logrus.Fields{"code": e.Code()}).WithError(e).Error("api error")
}
if err == models.ErrCallTimeoutServerBusy {
// TODO: Determine a better delay value here (perhaps ask Agent). For now 15 secs with
// the hopes that fnlb will land this on a better server immediately.
w.Header().Set("Retry-After", "15")
}
statuscode = e.Code()
} else if isGRPCError(err) {
log.WithError(err).Info("gRPC error received")
statuscode = http.StatusInternalServerError
err = ErrInternalServerError
} else {
log.WithError(err).WithFields(logrus.Fields{"stack": string(debug.Stack())}).Error("internal server error")
statuscode = http.StatusInternalServerError
err = ErrInternalServerError
}
WriteError(ctx, w, statuscode, err)
}
// WriteError easy way to do standard error response, but can set statuscode and error message easier than handleErrorResponse
func WriteError(ctx context.Context, w http.ResponseWriter, statuscode int, err error) {
log := common.Logger(ctx)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(statuscode)
err = json.NewEncoder(w).Encode(simpleError(err))
if err != nil {
log.WithError(err).Errorln("error encoding error json")
}
}
// isGRPCError inspect the error to verify if it is gRPC status and return a bool as results
// of this operation true means the error is a gRPC error false that it is not.
func isGRPCError(err error) bool {
_, ok := status.FromError(err)
return ok
}