Skip to content

Commit 257247a

Browse files
committed
UPSTREAM: <carry>: add http logging for kubelet metrics endpoint
1 parent 9c2642e commit 257247a

File tree

2 files changed

+86
-4
lines changed

2 files changed

+86
-4
lines changed

pkg/kubelet/server/server.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -474,15 +474,17 @@ func (s *Server) InstallAuthNotRequiredHandlers() {
474474
r.RawMustRegister(metrics.NewPrometheusCollector(prometheusHostAdapter{s.host}, containerPrometheusLabelsFunc(s.host), includedMetrics, clock.RealClock{}, cadvisorOpts))
475475
}
476476
s.restfulCont.Handle(cadvisorMetricsPath,
477-
compbasemetrics.HandlerFor(r, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError}),
478-
)
477+
WithHTTPLogging(
478+
compbasemetrics.HandlerFor(r, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError}),
479+
))
479480

480481
s.addMetricsBucketMatcher("metrics/resource")
481482
resourceRegistry := compbasemetrics.NewKubeRegistry()
482483
resourceRegistry.CustomMustRegister(collectors.NewResourceMetricsCollector(s.resourceAnalyzer))
483484
s.restfulCont.Handle(resourceMetricsPath,
484-
compbasemetrics.HandlerFor(resourceRegistry, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError}),
485-
)
485+
WithHTTPLogging(
486+
compbasemetrics.HandlerFor(resourceRegistry, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError}),
487+
))
486488

487489
// prober metrics are exposed under a different endpoint
488490

pkg/kubelet/server/server_patch.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package server
2+
3+
import (
4+
"net/http"
5+
"time"
6+
7+
"k8s.io/apiserver/pkg/audit"
8+
"k8s.io/apiserver/pkg/endpoints/responsewriter"
9+
"k8s.io/klog/v2"
10+
)
11+
12+
func WithHTTPLogging(handler http.Handler) http.Handler {
13+
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
14+
logger := &httpLogger{
15+
req: req,
16+
w: w,
17+
startedAt: time.Now(),
18+
}
19+
defer logger.log()
20+
21+
w = responsewriter.WrapForHTTP1Or2(logger)
22+
handler.ServeHTTP(w, req)
23+
})
24+
}
25+
26+
type httpLogger struct {
27+
req *http.Request
28+
w http.ResponseWriter
29+
30+
startedAt time.Time
31+
statusRecorded bool
32+
statusCode int
33+
}
34+
35+
var _ http.ResponseWriter = &httpLogger{}
36+
var _ responsewriter.UserProvidedDecorator = &httpLogger{}
37+
38+
func (l *httpLogger) Unwrap() http.ResponseWriter {
39+
return l.w
40+
}
41+
42+
// Header implements http.ResponseWriter.
43+
func (l *httpLogger) Header() http.Header {
44+
return l.w.Header()
45+
}
46+
47+
// Write implements http.ResponseWriter.
48+
func (l *httpLogger) Write(b []byte) (int, error) {
49+
if !l.statusRecorded {
50+
l.record(http.StatusOK) // Default if WriteHeader hasn't been called
51+
}
52+
return l.w.Write(b)
53+
}
54+
55+
// WriteHeader implements http.ResponseWriter.
56+
func (l *httpLogger) WriteHeader(status int) {
57+
l.record(status)
58+
l.w.WriteHeader(status)
59+
}
60+
61+
func (l *httpLogger) record(status int) {
62+
l.statusCode = status
63+
l.statusRecorded = true
64+
}
65+
66+
func (l *httpLogger) log() {
67+
latency := time.Since(l.startedAt)
68+
auditID := audit.GetAuditIDTruncated(l.req.Context())
69+
70+
kvs := []interface{}{
71+
"method", l.req.Method,
72+
"URI", l.req.RequestURI,
73+
"latency", latency,
74+
"userAgent", l.req.UserAgent(),
75+
"audit-ID", auditID,
76+
"srcIP", l.req.RemoteAddr,
77+
"status", l.statusCode,
78+
}
79+
klog.V(1).InfoSDepth(1, "HTTP", kvs...)
80+
}

0 commit comments

Comments
 (0)