forked from zitadel/zitadel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
http_handler.go
130 lines (114 loc) · 3.26 KB
/
http_handler.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
package metrics
import (
"net/http"
"strings"
"go.opentelemetry.io/otel/attribute"
)
const (
RequestCounter = "http.server.request_count"
RequestCountDescription = "Request counter"
TotalRequestCounter = "http.server.total_request_count"
TotalRequestDescription = "Total return code counter"
ReturnCodeCounter = "http.server.return_code_counter"
ReturnCodeCounterDescription = "Return code counter"
Method = "method"
URI = "uri"
ReturnCode = "return_code"
)
type Handler struct {
handler http.Handler
methods []MetricType
filters []Filter
}
type MetricType int32
const (
MetricTypeTotalCount MetricType = iota
MetricTypeStatusCode
MetricTypeRequestCount
)
type StatusRecorder struct {
http.ResponseWriter
Status int
}
func (r *StatusRecorder) WriteHeader(status int) {
r.Status = status
r.ResponseWriter.WriteHeader(status)
}
type Filter func(*http.Request) bool
func NewMetricsHandler(handler http.Handler, metricMethods []MetricType, ignoredEndpoints ...string) http.Handler {
h := Handler{
handler: handler,
methods: metricMethods,
}
if len(ignoredEndpoints) > 0 {
h.filters = append(h.filters, shouldNotIgnore(ignoredEndpoints...))
}
return &h
}
// ServeHTTP serves HTTP requests (http.Handler)
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(h.methods) == 0 {
h.handler.ServeHTTP(w, r)
return
}
for _, f := range h.filters {
if !f(r) {
// Simply pass through to the handler if a filter rejects the request
h.handler.ServeHTTP(w, r)
return
}
}
recorder := &StatusRecorder{
ResponseWriter: w,
Status: 200,
}
h.handler.ServeHTTP(recorder, r)
if h.containsMetricsMethod(MetricTypeRequestCount) {
RegisterRequestCounter(r)
}
if h.containsMetricsMethod(MetricTypeTotalCount) {
RegisterTotalRequestCounter(r)
}
if h.containsMetricsMethod(MetricTypeStatusCode) {
RegisterRequestCodeCounter(recorder, r)
}
}
func (h *Handler) containsMetricsMethod(method MetricType) bool {
for _, m := range h.methods {
if m == method {
return true
}
}
return false
}
func RegisterRequestCounter(r *http.Request) {
var labels = map[string]attribute.Value{
URI: attribute.StringValue(strings.Split(r.RequestURI, "?")[0]),
Method: attribute.StringValue(r.Method),
}
RegisterCounter(RequestCounter, RequestCountDescription)
AddCount(r.Context(), RequestCounter, 1, labels)
}
func RegisterTotalRequestCounter(r *http.Request) {
RegisterCounter(TotalRequestCounter, TotalRequestDescription)
AddCount(r.Context(), TotalRequestCounter, 1, nil)
}
func RegisterRequestCodeCounter(recorder *StatusRecorder, r *http.Request) {
var labels = map[string]attribute.Value{
URI: attribute.StringValue(strings.Split(r.RequestURI, "?")[0]),
Method: attribute.StringValue(r.Method),
ReturnCode: attribute.IntValue(recorder.Status),
}
RegisterCounter(ReturnCodeCounter, ReturnCodeCounterDescription)
AddCount(r.Context(), ReturnCodeCounter, 1, labels)
}
func shouldNotIgnore(endpoints ...string) func(r *http.Request) bool {
return func(r *http.Request) bool {
for _, endpoint := range endpoints {
if strings.HasPrefix(r.URL.RequestURI(), endpoint) {
return false
}
}
return true
}
}