/
error.go
102 lines (85 loc) · 2.37 KB
/
error.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package render
import (
"net/http"
"github.com/delving/hub3/ikuzo/domain"
"github.com/getsentry/sentry-go"
"github.com/rs/zerolog"
"github.com/rs/zerolog/hlog"
"github.com/rs/zerolog/log"
)
// DefaultConfig is a package-level variable set to our default Logger. We do this
// because it allows you to set your own logger when no logger is supplied with
// the ErrorConfig.
var DefaultConfig = ErrorConfig{
Log: &log.Logger,
StatusCode: http.StatusInternalServerError,
Message: "unable to handle request",
}
type ErrorConfig struct {
Log *zerolog.Logger
StatusCode int
Message string
DatasetID string
OrgID string
PreventBubble bool // prevent message from being logged or sent to sentry
}
func (ec *ErrorConfig) deepCopy() *ErrorConfig {
return &ErrorConfig{
Log: ec.Log,
StatusCode: ec.StatusCode,
Message: ec.Message,
DatasetID: ec.DatasetID,
OrgID: ec.OrgID,
PreventBubble: ec.PreventBubble,
}
}
type errorResponse struct {
Status string `json:"status"`
Code int `json:"code"`
Message string `json:"message"`
Description string `json:"description,omitempty"`
}
func Error(w http.ResponseWriter, r *http.Request, err error, cfg *ErrorConfig) {
if cfg == nil {
cfg = DefaultConfig.deepCopy()
}
if cfg.StatusCode == http.StatusNotFound {
cfg.PreventBubble = true
}
msg := "unable to handle request"
if cfg.Message != "" {
msg = cfg.Message
}
if cfg.OrgID == "" {
orgID := domain.GetOrganizationID(r)
cfg.OrgID = orgID.String()
}
requestID, _ := hlog.IDFromRequest(r)
if !cfg.PreventBubble && cfg.Log != nil {
l := cfg.Log.Error().Err(err)
if cfg.DatasetID != "" {
l = l.Str("dataset_id", cfg.DatasetID)
}
l.Str("org_id", cfg.OrgID).Str("req_id", requestID.String()).Msg(msg)
}
hub := sentry.GetHubFromContext(r.Context())
if hub != nil && !cfg.PreventBubble {
hub.ConfigureScope(func(scope *sentry.Scope) {
scope.SetContext("Hub3", map[string]interface{}{
"orgID": cfg.OrgID,
"datasetID": cfg.DatasetID,
"requestID": requestID,
})
})
hub.CaptureException(err)
}
Status(r, cfg.StatusCode)
resp := errorResponse{
Status: http.StatusText(cfg.StatusCode),
Code: cfg.StatusCode,
Message: err.Error(),
Description: cfg.Message,
}
w.Header().Set("X-Content-Type-Options", "nosniff")
JSON(w, r, resp)
}