mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-04 10:47:25 +00:00
Merge pull request #105734 from marseel/fix/race_condition
Fix race condition in logging when request times out
This commit is contained in:
@@ -24,6 +24,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||||
@@ -54,18 +55,22 @@ const respLoggerContextKey respLoggerContextKeyType = iota
|
|||||||
// the http.ResponseWriter. We can recover panics from go-restful, and
|
// the http.ResponseWriter. We can recover panics from go-restful, and
|
||||||
// the logging value is questionable.
|
// the logging value is questionable.
|
||||||
type respLogger struct {
|
type respLogger struct {
|
||||||
hijacked bool
|
hijacked bool
|
||||||
statusRecorded bool
|
statusRecorded bool
|
||||||
status int
|
status int
|
||||||
statusStack string
|
statusStack string
|
||||||
|
// mutex is used when accessing addedInfo and addedKeyValuePairs.
|
||||||
|
// They can be modified by other goroutine when logging happens (in case of request timeout)
|
||||||
|
mutex sync.Mutex
|
||||||
addedInfo strings.Builder
|
addedInfo strings.Builder
|
||||||
addedKeyValuePairs []interface{}
|
addedKeyValuePairs []interface{}
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
|
|
||||||
captureErrorOutput bool
|
captureErrorOutput bool
|
||||||
|
|
||||||
req *http.Request
|
req *http.Request
|
||||||
w http.ResponseWriter
|
userAgent string
|
||||||
|
w http.ResponseWriter
|
||||||
|
|
||||||
logStacktracePred StacktracePred
|
logStacktracePred StacktracePred
|
||||||
}
|
}
|
||||||
@@ -141,6 +146,7 @@ func newLoggedWithStartTime(req *http.Request, w http.ResponseWriter, startTime
|
|||||||
logger := &respLogger{
|
logger := &respLogger{
|
||||||
startTime: startTime,
|
startTime: startTime,
|
||||||
req: req,
|
req: req,
|
||||||
|
userAgent: req.UserAgent(),
|
||||||
w: w,
|
w: w,
|
||||||
logStacktracePred: DefaultStacktracePred,
|
logStacktracePred: DefaultStacktracePred,
|
||||||
}
|
}
|
||||||
@@ -192,6 +198,8 @@ 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.mutex.Lock()
|
||||||
|
defer rl.mutex.Unlock()
|
||||||
rl.addedInfo.WriteString("\n")
|
rl.addedInfo.WriteString("\n")
|
||||||
rl.addedInfo.WriteString(fmt.Sprintf(format, data...))
|
rl.addedInfo.WriteString(fmt.Sprintf(format, data...))
|
||||||
}
|
}
|
||||||
@@ -203,6 +211,8 @@ func AddInfof(ctx context.Context, format string, data ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rl *respLogger) AddKeyValue(key string, value interface{}) {
|
func (rl *respLogger) AddKeyValue(key string, value interface{}) {
|
||||||
|
rl.mutex.Lock()
|
||||||
|
defer rl.mutex.Unlock()
|
||||||
rl.addedKeyValuePairs = append(rl.addedKeyValuePairs, key, value)
|
rl.addedKeyValuePairs = append(rl.addedKeyValuePairs, key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,10 +245,18 @@ func (rl *respLogger) Log() {
|
|||||||
"verb", verb,
|
"verb", verb,
|
||||||
"URI", rl.req.RequestURI,
|
"URI", rl.req.RequestURI,
|
||||||
"latency", latency,
|
"latency", latency,
|
||||||
"userAgent", rl.req.UserAgent(),
|
// We can't get UserAgent from rl.req.UserAgent() here as it accesses headers map,
|
||||||
|
// which can be modified in another goroutine when apiserver request times out.
|
||||||
|
// For example authentication filter modifies request's headers,
|
||||||
|
// This can cause apiserver to crash with unrecoverable fatal error.
|
||||||
|
// More info about concurrent read and write for maps: https://golang.org/doc/go1.6#runtime
|
||||||
|
"userAgent", rl.userAgent,
|
||||||
"audit-ID", auditID,
|
"audit-ID", auditID,
|
||||||
"srcIP", rl.req.RemoteAddr,
|
"srcIP", rl.req.RemoteAddr,
|
||||||
}
|
}
|
||||||
|
// Lock for accessing addedKeyValuePairs and addedInfo
|
||||||
|
rl.mutex.Lock()
|
||||||
|
defer rl.mutex.Unlock()
|
||||||
keysAndValues = append(keysAndValues, rl.addedKeyValuePairs...)
|
keysAndValues = append(keysAndValues, rl.addedKeyValuePairs...)
|
||||||
|
|
||||||
if rl.hijacked {
|
if rl.hijacked {
|
||||||
|
Reference in New Issue
Block a user