Add logging of filters to api calls logs
Kubernetes-commit: 7e01b7260ac5cc20c1fc236cae220857726dc330
This commit is contained in:
parent
9eb1679911
commit
489e43cad9
|
@ -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())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue