forked from grafana/grafana
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrequest_metadata.go
134 lines (107 loc) · 3.54 KB
/
request_metadata.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package requestmeta
import (
"context"
"net/http"
"github.com/grafana/grafana/pkg/web"
)
const (
TeamAlerting = "alerting"
TeamAuth = "auth"
TeamBackend = "backend"
)
type StatusSource string
const (
StatusSourceServer StatusSource = "server"
StatusSourceDownstream StatusSource = "downstream"
)
type RequestMetaData struct {
Team string
StatusSource StatusSource
SLOGroup SLOGroup
}
type SLOGroup string
const (
// SLOGroupHighFast is the default slo group for handlers in Grafana
// Most handlers should respond quickly
SLOGroupHighFast SLOGroup = "high-fast"
// SLOGroupHighMedium is used for handlers that might take some
// time to respond.
SLOGroupHighMedium SLOGroup = "high-medium"
// SLOGroupHighSlow is used by handlers that proxies requests downstream.
// We expect an high successrate but without latency garantess
SLOGroupHighSlow SLOGroup = "high-slow"
// SLOGroupLow should only be used for experimental features
// that might not be stable enough for our normal SLO
SLOGroupLow SLOGroup = "low"
// SLOGroupNone means that errors are expect for this handler and
// it should not be included in the SLO.
SLOGroupNone SLOGroup = "none"
)
type rMDContextKey struct{}
var requestMetaDataContextKey = rMDContextKey{}
// SetupRequestMetadata injects defaul request metadata values
// on the request context.
func SetupRequestMetadata() web.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rmd := defaultRequestMetadata()
ctx := SetRequestMetaData(r.Context(), rmd)
*r = *r.WithContext(ctx)
next.ServeHTTP(w, r)
})
}
}
// GetRequestMetaData returns the request metadata for the context.
// if request metadata is missing it will return the default values.
func GetRequestMetaData(ctx context.Context) *RequestMetaData {
val := ctx.Value(requestMetaDataContextKey)
value, ok := val.(*RequestMetaData)
if ok {
return value
}
rmd := defaultRequestMetadata()
return &rmd
}
// SetRequestMetaData sets the request metadata for the context.
func SetRequestMetaData(ctx context.Context, rmd RequestMetaData) context.Context {
return context.WithValue(ctx, requestMetaDataContextKey, &rmd)
}
// SetOwner returns an `web.Handler` that sets the team name for an request.
func SetOwner(team string) web.Handler {
return func(w http.ResponseWriter, r *http.Request) {
v := GetRequestMetaData(r.Context())
v.Team = team
}
}
// WithDownstreamStatusSource sets the StatusSource field of the [RequestMetaData] for the
// context to [StatusSourceDownstream].
func WithDownstreamStatusSource(ctx context.Context) {
v := GetRequestMetaData(ctx)
v.StatusSource = StatusSourceDownstream
}
// WithStatusSource sets the StatusSource field of the [RequestMetaData] for the
// context based on the provided statusCode.
// If statusCode >= 500 then [StatusSourceDownstream].
// If statusCode < 500 then [StatusSourceServer].
func WithStatusSource(ctx context.Context, statusCode int) {
v := GetRequestMetaData(ctx)
if statusCode >= 500 {
v.StatusSource = StatusSourceDownstream
return
}
v.StatusSource = StatusSourceServer
}
func defaultRequestMetadata() RequestMetaData {
return RequestMetaData{
Team: TeamBackend,
StatusSource: StatusSourceServer,
SLOGroup: SLOGroupHighFast,
}
}
// SetSLOGroup creates an middleware that sets the SLOGroup for the request
func SetSLOGroup(lvl SLOGroup) web.Handler {
return func(w http.ResponseWriter, r *http.Request) {
v := GetRequestMetaData(r.Context())
v.SLOGroup = lvl
}
}