Skip to content
This repository was archived by the owner on May 17, 2024. It is now read-only.

Commit 301e84d

Browse files
committed
Adds metrics package to expose proxy metrics
Signed-off-by: JoshVanL <[email protected]>
1 parent 46d2f79 commit 301e84d

File tree

1 file changed

+218
-0
lines changed

1 file changed

+218
-0
lines changed

pkg/metrics/metrics.go

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
// Copyright Jetstack Ltd. See LICENSE for details.
2+
package metrics
3+
4+
import (
5+
"context"
6+
"fmt"
7+
"net"
8+
"net/http"
9+
"strconv"
10+
"time"
11+
12+
"github.com/prometheus/client_golang/prometheus"
13+
"github.com/prometheus/client_golang/prometheus/promhttp"
14+
"k8s.io/klog"
15+
)
16+
17+
const (
18+
promNamespace = "kube_oidc_proxy"
19+
)
20+
21+
type Metrics struct {
22+
*http.Server
23+
24+
registry *prometheus.Registry
25+
26+
// Metrics for incoming client requests
27+
clientRequests *prometheus.CounterVec
28+
clientDuration *prometheus.HistogramVec
29+
30+
// Metrics for outgoing server requests
31+
serverRequests *prometheus.CounterVec
32+
serverDuration *prometheus.HistogramVec
33+
34+
// Metrics for authentication of incoming requests
35+
oidcAuthCount *prometheus.CounterVec
36+
37+
// Metrics for token reviews
38+
tokenReviewDuration *prometheus.HistogramVec
39+
}
40+
41+
func New() *Metrics {
42+
var (
43+
clientRequests = prometheus.NewCounterVec(
44+
prometheus.CounterOpts{
45+
Namespace: promNamespace,
46+
Name: "http_client_requests",
47+
Help: "The number of requests for incomming requests.",
48+
},
49+
[]string{"code", "path", "remote_address"},
50+
)
51+
clientDuration = prometheus.NewHistogramVec(
52+
prometheus.HistogramOpts{
53+
Namespace: promNamespace,
54+
Name: "http_client_duration_seconds",
55+
Help: "The duration in seconds for incoming client requests to be responded to.",
56+
Buckets: prometheus.LinearBuckets(.000, .05, 30),
57+
},
58+
[]string{"remote_address"},
59+
)
60+
61+
serverRequests = prometheus.NewCounterVec(
62+
prometheus.CounterOpts{
63+
Namespace: promNamespace,
64+
Name: "http_server_requests",
65+
Help: "The requests for outgoing server requests.",
66+
},
67+
[]string{"code", "path", "remote_address"},
68+
)
69+
serverDuration = prometheus.NewHistogramVec(
70+
prometheus.HistogramOpts{
71+
Namespace: promNamespace,
72+
Name: "http_server_duration_seconds",
73+
Help: "The duration in seconds for outgoing server requests to be responded to.",
74+
Buckets: prometheus.LinearBuckets(.000, .05, 30),
75+
},
76+
[]string{"remote_address"},
77+
)
78+
79+
oidcAuthCount = prometheus.NewCounterVec(
80+
prometheus.CounterOpts{
81+
Namespace: promNamespace,
82+
Name: "oidc_authentication_count",
83+
Help: "The count for OIDC authentication. Authenticated requests are 1, else 0.",
84+
},
85+
[]string{"authenticated", "remote_address", "user"},
86+
)
87+
88+
tokenReviewDuration = prometheus.NewHistogramVec(
89+
prometheus.HistogramOpts{
90+
Namespace: promNamespace,
91+
Name: "token_review_duration_seconds",
92+
Help: "The duration in seconds for a token review lookup. Authenticated requests are 1, else 0.",
93+
Buckets: prometheus.LinearBuckets(.000, .05, 30),
94+
},
95+
[]string{"authenticated", "code", "remote_address", "user"},
96+
)
97+
)
98+
99+
registry := prometheus.NewRegistry()
100+
registry.MustRegister(clientRequests)
101+
registry.MustRegister(clientDuration)
102+
registry.MustRegister(serverRequests)
103+
registry.MustRegister(serverDuration)
104+
registry.MustRegister(oidcAuthCount)
105+
registry.MustRegister(tokenReviewDuration)
106+
107+
return &Metrics{
108+
registry: registry,
109+
110+
clientRequests: clientRequests,
111+
clientDuration: clientDuration,
112+
113+
serverRequests: serverRequests,
114+
serverDuration: serverDuration,
115+
116+
oidcAuthCount: oidcAuthCount,
117+
tokenReviewDuration: tokenReviewDuration,
118+
}
119+
}
120+
121+
// Start will register the Prometheus metrics, and start the Prometheus server
122+
func (m *Metrics) Start(listenAddress string) error {
123+
router := http.NewServeMux()
124+
router.Handle("/metrics", promhttp.HandlerFor(m.registry, promhttp.HandlerOpts{}))
125+
126+
ln, err := net.Listen("tcp", listenAddress)
127+
if err != nil {
128+
return err
129+
}
130+
131+
m.Server = &http.Server{
132+
Addr: ln.Addr().String(),
133+
ReadTimeout: 8 * time.Second,
134+
WriteTimeout: 8 * time.Second,
135+
MaxHeaderBytes: 1 << 15, // 1 MiB
136+
Handler: router,
137+
}
138+
139+
go func() {
140+
klog.Infof("serving metrics on %s/metrics", ln.Addr())
141+
142+
if err := m.Serve(ln); err != nil {
143+
klog.Errorf("failed to serve prometheus metrics: %s", err)
144+
return
145+
}
146+
}()
147+
148+
return nil
149+
}
150+
151+
func (m *Metrics) Shutdown() error {
152+
// If metrics server is not started than exit early
153+
if m.Server == nil {
154+
return nil
155+
}
156+
157+
klog.Info("shutting down Prometheus metrics server...")
158+
159+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
160+
defer cancel()
161+
162+
if err := m.Server.Shutdown(ctx); err != nil {
163+
return fmt.Errorf("prometheus metrics server shutdown failed: %s", err)
164+
}
165+
166+
klog.Info("prometheus metrics server gracefully stopped")
167+
168+
return nil
169+
}
170+
171+
func (m *Metrics) ObserveClient(code int, path, remoteAddress string, duration time.Duration) {
172+
m.clientRequests.With(prometheus.Labels{
173+
"code": strconv.Itoa(code),
174+
"path": path,
175+
"remote_address": remoteAddress,
176+
}).Inc()
177+
178+
m.clientDuration.With(prometheus.Labels{
179+
"remote_address": remoteAddress,
180+
}).Observe(duration.Seconds())
181+
}
182+
183+
func (m *Metrics) ObserveServer(code int, path, remoteAddress string, duration time.Duration) {
184+
m.serverRequests.With(prometheus.Labels{
185+
"code": strconv.Itoa(code),
186+
"path": path,
187+
"remote_address": remoteAddress,
188+
}).Inc()
189+
190+
m.serverDuration.With(prometheus.Labels{
191+
"remote_address": remoteAddress,
192+
}).Observe(duration.Seconds())
193+
}
194+
195+
func (m *Metrics) IncrementOIDCAuthCount(authenticated bool, remoteAddress, user string) {
196+
m.oidcAuthCount.With(prometheus.Labels{
197+
"authenticated": boolToIntString(authenticated),
198+
"remote_address": remoteAddress,
199+
"user": user,
200+
}).Inc()
201+
}
202+
203+
func (m *Metrics) ObserveTokenReivewLookup(authenticated bool, code int, remoteAddress, user string, duration time.Duration) {
204+
m.tokenReviewDuration.With(prometheus.Labels{
205+
"authenticated": boolToIntString(authenticated),
206+
"code": strconv.Itoa(code),
207+
"remote_address": remoteAddress,
208+
"user": user,
209+
}).Observe(duration.Seconds())
210+
}
211+
212+
func boolToIntString(b bool) string {
213+
var i int
214+
if b {
215+
i = 1
216+
}
217+
return strconv.Itoa(i)
218+
}

0 commit comments

Comments
 (0)