Add logging of filters to api calls logs

Kubernetes-commit: 7e01b7260ac5cc20c1fc236cae220857726dc330
This commit is contained in:
Marcel Zięba 2021-05-17 11:52:33 +00:00 committed by Kubernetes Publisher
parent 9eb1679911
commit 489e43cad9
2 changed files with 30 additions and 10 deletions

View File

@ -24,6 +24,8 @@ import (
utilclock "k8s.io/apimachinery/pkg/util/clock" utilclock "k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apiserver/pkg/endpoints/metrics" "k8s.io/apiserver/pkg/endpoints/metrics"
apirequest "k8s.io/apiserver/pkg/endpoints/request" apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/server/httplog"
"k8s.io/klog/v2"
) )
type requestFilterRecordKeyType int type requestFilterRecordKeyType int
@ -31,6 +33,8 @@ type requestFilterRecordKeyType int
// requestFilterRecordKey is the context key for a request filter record struct. // requestFilterRecordKey is the context key for a request filter record struct.
const requestFilterRecordKey requestFilterRecordKeyType = iota const requestFilterRecordKey requestFilterRecordKeyType = iota
const minFilterLatencyToLog = 100 * time.Millisecond
type requestFilterRecord struct { type requestFilterRecord struct {
name string name string
startedTimestamp time.Time startedTimestamp time.Time
@ -57,7 +61,11 @@ func TrackStarted(handler http.Handler, name string) http.Handler {
// it updates the corresponding metric with the filter latency duration. // it updates the corresponding metric with the filter latency duration.
func TrackCompleted(handler http.Handler) http.Handler { func TrackCompleted(handler http.Handler) http.Handler {
return trackCompleted(handler, utilclock.RealClock{}, func(ctx context.Context, fr *requestFilterRecord, completedAt time.Time) { return trackCompleted(handler, utilclock.RealClock{}, func(ctx context.Context, fr *requestFilterRecord, completedAt time.Time) {
metrics.RecordFilterLatency(ctx, fr.name, completedAt.Sub(fr.startedTimestamp)) latency := completedAt.Sub(fr.startedTimestamp)
metrics.RecordFilterLatency(ctx, fr.name, latency)
if klog.V(3).Enabled() && latency > minFilterLatencyToLog {
httplog.AddInfof(ctx, "%s=%s", fr.name, latency.String())
}
}) })
} }

View File

@ -23,6 +23,7 @@ import (
"net" "net"
"net/http" "net/http"
"runtime" "runtime"
"strings"
"time" "time"
"k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/endpoints/request"
@ -52,7 +53,7 @@ type respLogger struct {
statusRecorded bool statusRecorded bool
status int status int
statusStack string statusStack string
addedInfo string addedInfo strings.Builder
startTime time.Time startTime time.Time
captureErrorOutput bool captureErrorOutput bool
@ -83,7 +84,7 @@ func DefaultStacktracePred(status int) bool {
func WithLogging(handler http.Handler, pred StacktracePred) http.Handler { func WithLogging(handler http.Handler, pred StacktracePred) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context() ctx := req.Context()
if old := respLoggerFromContext(req); old != nil { if old := respLoggerFromRequest(req); old != nil {
panic("multiple WithLogging calls!") panic("multiple WithLogging calls!")
} }
@ -103,8 +104,7 @@ func WithLogging(handler http.Handler, pred StacktracePred) http.Handler {
} }
// respLoggerFromContext returns the respLogger or nil. // respLoggerFromContext returns the respLogger or nil.
func respLoggerFromContext(req *http.Request) *respLogger { func respLoggerFromContext(ctx context.Context) *respLogger {
ctx := req.Context()
val := ctx.Value(respLoggerContextKey) val := ctx.Value(respLoggerContextKey)
if rl, ok := val.(*respLogger); ok { if rl, ok := val.(*respLogger); ok {
return rl return rl
@ -112,6 +112,10 @@ func respLoggerFromContext(req *http.Request) *respLogger {
return nil return nil
} }
func respLoggerFromRequest(req *http.Request) *respLogger {
return respLoggerFromContext(req.Context())
}
func newLoggedWithStartTime(req *http.Request, w http.ResponseWriter, startTime time.Time) *respLogger { func newLoggedWithStartTime(req *http.Request, w http.ResponseWriter, startTime time.Time) *respLogger {
return &respLogger{ return &respLogger{
startTime: startTime, startTime: startTime,
@ -130,7 +134,7 @@ func newLogged(req *http.Request, w http.ResponseWriter) *respLogger {
// then a passthroughLogger will be created which will log to stdout immediately // then a passthroughLogger will be created which will log to stdout immediately
// when Addf is called. // when Addf is called.
func LogOf(req *http.Request, w http.ResponseWriter) logger { func LogOf(req *http.Request, w http.ResponseWriter) logger {
if rl := respLoggerFromContext(req); rl != nil { if rl := respLoggerFromRequest(req); rl != nil {
return rl return rl
} }
return &passthroughLogger{} return &passthroughLogger{}
@ -138,7 +142,7 @@ func LogOf(req *http.Request, w http.ResponseWriter) logger {
// Unlogged returns the original ResponseWriter, or w if it is not our inserted logger. // Unlogged returns the original ResponseWriter, or w if it is not our inserted logger.
func Unlogged(req *http.Request, w http.ResponseWriter) http.ResponseWriter { func Unlogged(req *http.Request, w http.ResponseWriter) http.ResponseWriter {
if rl := respLoggerFromContext(req); rl != nil { if rl := respLoggerFromRequest(req); rl != nil {
return rl.w return rl.w
} }
return w return w
@ -166,7 +170,14 @@ func StatusIsNot(statuses ...int) StacktracePred {
// Addf adds additional data to be logged with this request. // Addf adds additional data to be logged with this request.
func (rl *respLogger) Addf(format string, data ...interface{}) { func (rl *respLogger) Addf(format string, data ...interface{}) {
rl.addedInfo += "\n" + fmt.Sprintf(format, data...) rl.addedInfo.WriteString("\n")
rl.addedInfo.WriteString(fmt.Sprintf(format, data...))
}
func AddInfof(ctx context.Context, format string, data ...interface{}) {
if rl := respLoggerFromContext(ctx); rl != nil {
rl.Addf(format, data...)
}
} }
func (rl *respLogger) LogArgs() []interface{} { func (rl *respLogger) LogArgs() []interface{} {
@ -196,8 +207,9 @@ func (rl *respLogger) LogArgs() []interface{} {
args = append(args, "statusStack", rl.statusStack) args = append(args, "statusStack", rl.statusStack)
} }
if len(rl.addedInfo) > 0 { info := rl.addedInfo.String()
args = append(args, "addedInfo", rl.addedInfo) if len(info) > 0 {
args = append(args, "addedInfo", info)
} }
return args return args
} }