feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

6
vendor/k8s.io/klog/v2/.golangci.yaml generated vendored Normal file
View File

@@ -0,0 +1,6 @@
linters:
disable-all: true
enable: # sorted alphabetical
- gofmt
- misspell
- revive

30
vendor/k8s.io/klog/v2/contextual.go generated vendored
View File

@@ -70,11 +70,14 @@ func SetLogger(logger logr.Logger) {
// routing log entries through klogr into klog and then into the actual Logger
// backend.
func SetLoggerWithOptions(logger logr.Logger, opts ...LoggerOption) {
logging.logger = &logger
logging.loggerOptions = loggerOptions{}
for _, opt := range opts {
opt(&logging.loggerOptions)
}
logging.logger = &logWriter{
Logger: logger,
writeKlogBuffer: logging.loggerOptions.writeKlogBuffer,
}
}
// ContextualLogger determines whether the logger passed to
@@ -93,6 +96,22 @@ func FlushLogger(flush func()) LoggerOption {
}
}
// WriteKlogBuffer sets a callback that will be invoked by klog to write output
// produced by non-structured log calls like Infof.
//
// The buffer will contain exactly the same data that klog normally would write
// into its own output stream(s). In particular this includes the header, if
// klog is configured to write one. The callback then can divert that data into
// its own output streams. The buffer may or may not end in a line break.
//
// Without such a callback, klog will call the logger's Info or Error method
// with just the message string (i.e. no header).
func WriteKlogBuffer(write func([]byte)) LoggerOption {
return func(o *loggerOptions) {
o.writeKlogBuffer = write
}
}
// LoggerOption implements the functional parameter paradigm for
// SetLoggerWithOptions.
type LoggerOption func(o *loggerOptions)
@@ -100,6 +119,13 @@ type LoggerOption func(o *loggerOptions)
type loggerOptions struct {
contextualLogger bool
flush func()
writeKlogBuffer func([]byte)
}
// logWriter combines a logger (always set) with a write callback (optional).
type logWriter struct {
Logger
writeKlogBuffer func([]byte)
}
// ClearLogger removes a backing Logger implementation if one was set earlier
@@ -152,7 +178,7 @@ func Background() Logger {
if logging.loggerOptions.contextualLogger {
// Is non-nil because logging.loggerOptions.contextualLogger is
// only true if a logger was set.
return *logging.logger
return logging.logger.Logger
}
return klogLogger

65
vendor/k8s.io/klog/v2/format.go generated vendored Normal file
View File

@@ -0,0 +1,65 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package klog
import (
"encoding/json"
"fmt"
"strings"
"github.com/go-logr/logr"
)
// Format wraps a value of an arbitrary type and implement fmt.Stringer and
// logr.Marshaler for them. Stringer returns pretty-printed JSON. MarshalLog
// returns the original value with a type that has no special methods, in
// particular no MarshalLog or MarshalJSON.
//
// Wrapping values like that is useful when the value has a broken
// implementation of these special functions (for example, a type which
// inherits String from TypeMeta, but then doesn't re-implement String) or the
// implementation produces output that is less readable or unstructured (for
// example, the generated String functions for Kubernetes API types).
func Format(obj interface{}) interface{} {
return formatAny{Object: obj}
}
type formatAny struct {
Object interface{}
}
func (f formatAny) String() string {
var buffer strings.Builder
encoder := json.NewEncoder(&buffer)
encoder.SetIndent("", " ")
if err := encoder.Encode(&f.Object); err != nil {
return fmt.Sprintf("error marshaling %T to JSON: %v", f, err)
}
return buffer.String()
}
func (f formatAny) MarshalLog() interface{} {
// Returning a pointer to a pointer ensures that zapr doesn't find a
// fmt.Stringer or logr.Marshaler when it checks the type of the
// value. It then falls back to reflection, which dumps the value being
// pointed to (JSON doesn't have pointers).
ptr := &f.Object
return &ptr
}
var _ fmt.Stringer = formatAny{}
var _ logr.Marshaler = formatAny{}

View File

@@ -30,14 +30,16 @@ import (
var (
// Pid is inserted into log headers. Can be overridden for tests.
Pid = os.Getpid()
// Time, if set, will be used instead of the actual current time.
Time *time.Time
)
// Buffer holds a single byte.Buffer for reuse. The zero value is ready for
// use. It also provides some helper methods for output formatting.
type Buffer struct {
bytes.Buffer
Tmp [64]byte // temporary byte array for creating headers.
next *Buffer
Tmp [64]byte // temporary byte array for creating headers.
}
var buffers = sync.Pool{
@@ -55,6 +57,17 @@ func GetBuffer() *Buffer {
// PutBuffer returns a buffer to the free list.
func PutBuffer(b *Buffer) {
if b.Len() >= 256 {
// Let big buffers die a natural death, without relying on
// sync.Pool behavior. The documentation implies that items may
// get deallocated while stored there ("If the Pool holds the
// only reference when this [= be removed automatically]
// happens, the item might be deallocated."), but
// https://github.com/golang/go/issues/23199 leans more towards
// having such a size limit.
return
}
buffers.Put(b)
}
@@ -99,7 +112,8 @@ func (buf *Buffer) someDigits(i, d int) int {
return copy(buf.Tmp[i:], buf.Tmp[j:])
}
// FormatHeader formats a log header using the provided file name and line number.
// FormatHeader formats a log header using the provided file name and line number
// and writes it into the buffer.
func (buf *Buffer) FormatHeader(s severity.Severity, file string, line int, now time.Time) {
if line < 0 {
line = 0 // not a real line number, but acceptable to someDigits
@@ -110,6 +124,9 @@ func (buf *Buffer) FormatHeader(s severity.Severity, file string, line int, now
// Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand.
// It's worth about 3X. Fprintf is hard.
if Time != nil {
now = *Time
}
_, month, day := now.Date()
hour, minute, second := now.Clock()
// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
@@ -135,3 +152,33 @@ func (buf *Buffer) FormatHeader(s severity.Severity, file string, line int, now
buf.Tmp[n+2] = ' '
buf.Write(buf.Tmp[:n+3])
}
// SprintHeader formats a log header and returns a string. This is a simpler
// version of FormatHeader for use in ktesting.
func (buf *Buffer) SprintHeader(s severity.Severity, now time.Time) string {
if s > severity.FatalLog {
s = severity.InfoLog // for safety.
}
// Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand.
// It's worth about 3X. Fprintf is hard.
if Time != nil {
now = *Time
}
_, month, day := now.Date()
hour, minute, second := now.Clock()
// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
buf.Tmp[0] = severity.Char[s]
buf.twoDigits(1, int(month))
buf.twoDigits(3, day)
buf.Tmp[5] = ' '
buf.twoDigits(6, hour)
buf.Tmp[8] = ':'
buf.twoDigits(9, minute)
buf.Tmp[11] = ':'
buf.twoDigits(12, second)
buf.Tmp[14] = '.'
buf.nDigits(6, 15, now.Nanosecond()/1000, '0')
buf.Tmp[21] = ']'
return string(buf.Tmp[:22])
}

View File

@@ -39,16 +39,6 @@ type Clock interface {
// Sleep sleeps for the provided duration d.
// Consider making the sleep interruptible by using 'select' on a context channel and a timer channel.
Sleep(d time.Duration)
// Tick returns the channel of a new Ticker.
// This method does not allow to free/GC the backing ticker. Use
// NewTicker from WithTicker instead.
Tick(d time.Duration) <-chan time.Time
}
// WithTicker allows for injecting fake or real clocks into code that
// needs to do arbitrary things based on time.
type WithTicker interface {
Clock
// NewTicker returns a new Ticker.
NewTicker(time.Duration) Ticker
}
@@ -66,7 +56,7 @@ type WithDelayedExecution interface {
// WithTickerAndDelayedExecution allows for injecting fake or real clocks
// into code that needs Ticker and AfterFunc functionality
type WithTickerAndDelayedExecution interface {
WithTicker
Clock
// AfterFunc executes f in its own goroutine after waiting
// for d duration and returns a Timer whose channel can be
// closed by calling Stop() on the Timer.
@@ -79,7 +69,7 @@ type Ticker interface {
Stop()
}
var _ = WithTicker(RealClock{})
var _ Clock = RealClock{}
// RealClock really calls time.Now()
type RealClock struct{}
@@ -115,13 +105,6 @@ func (RealClock) AfterFunc(d time.Duration, f func()) Timer {
}
}
// Tick is the same as time.Tick(d)
// This method does not allow to free/GC the backing ticker. Use
// NewTicker instead.
func (RealClock) Tick(d time.Duration) <-chan time.Time {
return time.Tick(d)
}
// NewTicker returns a new Ticker.
func (RealClock) NewTicker(d time.Duration) Ticker {
return &realTicker{

View File

@@ -18,6 +18,7 @@ package serialize
import (
"bytes"
"encoding/json"
"fmt"
"strconv"
@@ -95,9 +96,15 @@ func MergeKVs(first, second []interface{}) []interface{} {
return merged
}
type Formatter struct {
AnyToStringHook AnyToStringFunc
}
type AnyToStringFunc func(v interface{}) string
// MergeKVsInto is a variant of MergeKVs which directly formats the key/value
// pairs into a buffer.
func MergeAndFormatKVs(b *bytes.Buffer, first, second []interface{}) {
func (f Formatter) MergeAndFormatKVs(b *bytes.Buffer, first, second []interface{}) {
if len(first) == 0 && len(second) == 0 {
// Nothing to do at all.
return
@@ -107,7 +114,7 @@ func MergeAndFormatKVs(b *bytes.Buffer, first, second []interface{}) {
// Nothing to be overridden, second slice is well-formed
// and can be used directly.
for i := 0; i < len(second); i += 2 {
KVFormat(b, second[i], second[i+1])
f.KVFormat(b, second[i], second[i+1])
}
return
}
@@ -127,24 +134,28 @@ func MergeAndFormatKVs(b *bytes.Buffer, first, second []interface{}) {
if overrides[key] {
continue
}
KVFormat(b, key, first[i+1])
f.KVFormat(b, key, first[i+1])
}
// Round down.
l := len(second)
l = l / 2 * 2
for i := 1; i < l; i += 2 {
KVFormat(b, second[i-1], second[i])
f.KVFormat(b, second[i-1], second[i])
}
if len(second)%2 == 1 {
KVFormat(b, second[len(second)-1], missingValue)
f.KVFormat(b, second[len(second)-1], missingValue)
}
}
func MergeAndFormatKVs(b *bytes.Buffer, first, second []interface{}) {
Formatter{}.MergeAndFormatKVs(b, first, second)
}
const missingValue = "(MISSING)"
// KVListFormat serializes all key/value pairs into the provided buffer.
// A space gets inserted before the first pair and between each pair.
func KVListFormat(b *bytes.Buffer, keysAndValues ...interface{}) {
func (f Formatter) KVListFormat(b *bytes.Buffer, keysAndValues ...interface{}) {
for i := 0; i < len(keysAndValues); i += 2 {
var v interface{}
k := keysAndValues[i]
@@ -153,75 +164,41 @@ func KVListFormat(b *bytes.Buffer, keysAndValues ...interface{}) {
} else {
v = missingValue
}
KVFormat(b, k, v)
f.KVFormat(b, k, v)
}
}
// KVFormat serializes one key/value pair into the provided buffer.
// A space gets inserted before the pair.
func KVFormat(b *bytes.Buffer, k, v interface{}) {
b.WriteByte(' ')
// Keys are assumed to be well-formed according to
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments
// for the sake of performance. Keys with spaces,
// special characters, etc. will break parsing.
if sK, ok := k.(string); ok {
// Avoid one allocation when the key is a string, which
// normally it should be.
b.WriteString(sK)
} else {
b.WriteString(fmt.Sprintf("%s", k))
}
func KVListFormat(b *bytes.Buffer, keysAndValues ...interface{}) {
Formatter{}.KVListFormat(b, keysAndValues...)
}
// The type checks are sorted so that more frequently used ones
// come first because that is then faster in the common
// cases. In Kubernetes, ObjectRef (a Stringer) is more common
// than plain strings
// (https://github.com/kubernetes/kubernetes/pull/106594#issuecomment-975526235).
switch v := v.(type) {
case textWriter:
writeTextWriterValue(b, v)
case fmt.Stringer:
writeStringValue(b, true, StringerToString(v))
case string:
writeStringValue(b, true, v)
case error:
writeStringValue(b, true, ErrorToString(v))
case logr.Marshaler:
value := MarshalerToValue(v)
// A marshaler that returns a string is useful for
// delayed formatting of complex values. We treat this
// case like a normal string. This is useful for
// multi-line support.
//
// We could do this by recursively formatting a value,
// but that comes with the risk of infinite recursion
// if a marshaler returns itself. Instead we call it
// only once and rely on it returning the intended
// value directly.
switch value := value.(type) {
case string:
writeStringValue(b, true, value)
default:
writeStringValue(b, false, fmt.Sprintf("%+v", value))
}
case []byte:
// In https://github.com/kubernetes/klog/pull/237 it was decided
// to format byte slices with "%+q". The advantages of that are:
// - readable output if the bytes happen to be printable
// - non-printable bytes get represented as unicode escape
// sequences (\uxxxx)
//
// The downsides are that we cannot use the faster
// strconv.Quote here and that multi-line output is not
// supported. If developers know that a byte array is
// printable and they want multi-line output, they can
// convert the value to string before logging it.
b.WriteByte('=')
b.WriteString(fmt.Sprintf("%+q", v))
default:
writeStringValue(b, false, fmt.Sprintf("%+v", v))
func KVFormat(b *bytes.Buffer, k, v interface{}) {
Formatter{}.KVFormat(b, k, v)
}
// formatAny is the fallback formatter for a value. It supports a hook (for
// example, for YAML encoding) and itself uses JSON encoding.
func (f Formatter) formatAny(b *bytes.Buffer, v interface{}) {
b.WriteRune('=')
if f.AnyToStringHook != nil {
b.WriteString(f.AnyToStringHook(v))
return
}
formatAsJSON(b, v)
}
func formatAsJSON(b *bytes.Buffer, v interface{}) {
encoder := json.NewEncoder(b)
l := b.Len()
if err := encoder.Encode(v); err != nil {
// This shouldn't happen. We discard whatever the encoder
// wrote and instead dump an error string.
b.Truncate(l)
b.WriteString(fmt.Sprintf(`"<internal error: %v>"`, err))
return
}
// Remove trailing newline.
b.Truncate(b.Len() - 1)
}
// StringerToString converts a Stringer to a string,
@@ -261,7 +238,7 @@ func ErrorToString(err error) (ret string) {
}
func writeTextWriterValue(b *bytes.Buffer, v textWriter) {
b.WriteRune('=')
b.WriteByte('=')
defer func() {
if err := recover(); err != nil {
fmt.Fprintf(b, `"<panic: %s>"`, err)
@@ -270,18 +247,13 @@ func writeTextWriterValue(b *bytes.Buffer, v textWriter) {
v.WriteText(b)
}
func writeStringValue(b *bytes.Buffer, quote bool, v string) {
func writeStringValue(b *bytes.Buffer, v string) {
data := []byte(v)
index := bytes.IndexByte(data, '\n')
if index == -1 {
b.WriteByte('=')
if quote {
// Simple string, quote quotation marks and non-printable characters.
b.WriteString(strconv.Quote(v))
return
}
// Non-string with no line breaks.
b.WriteString(v)
// Simple string, quote quotation marks and non-printable characters.
b.WriteString(strconv.Quote(v))
return
}

View File

@@ -0,0 +1,97 @@
//go:build !go1.21
// +build !go1.21
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package serialize
import (
"bytes"
"fmt"
"github.com/go-logr/logr"
)
// KVFormat serializes one key/value pair into the provided buffer.
// A space gets inserted before the pair.
func (f Formatter) KVFormat(b *bytes.Buffer, k, v interface{}) {
// This is the version without slog support. Must be kept in sync with
// the version in keyvalues_slog.go.
b.WriteByte(' ')
// Keys are assumed to be well-formed according to
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments
// for the sake of performance. Keys with spaces,
// special characters, etc. will break parsing.
if sK, ok := k.(string); ok {
// Avoid one allocation when the key is a string, which
// normally it should be.
b.WriteString(sK)
} else {
b.WriteString(fmt.Sprintf("%s", k))
}
// The type checks are sorted so that more frequently used ones
// come first because that is then faster in the common
// cases. In Kubernetes, ObjectRef (a Stringer) is more common
// than plain strings
// (https://github.com/kubernetes/kubernetes/pull/106594#issuecomment-975526235).
switch v := v.(type) {
case textWriter:
writeTextWriterValue(b, v)
case fmt.Stringer:
writeStringValue(b, StringerToString(v))
case string:
writeStringValue(b, v)
case error:
writeStringValue(b, ErrorToString(v))
case logr.Marshaler:
value := MarshalerToValue(v)
// A marshaler that returns a string is useful for
// delayed formatting of complex values. We treat this
// case like a normal string. This is useful for
// multi-line support.
//
// We could do this by recursively formatting a value,
// but that comes with the risk of infinite recursion
// if a marshaler returns itself. Instead we call it
// only once and rely on it returning the intended
// value directly.
switch value := value.(type) {
case string:
writeStringValue(b, value)
default:
f.formatAny(b, value)
}
case []byte:
// In https://github.com/kubernetes/klog/pull/237 it was decided
// to format byte slices with "%+q". The advantages of that are:
// - readable output if the bytes happen to be printable
// - non-printable bytes get represented as unicode escape
// sequences (\uxxxx)
//
// The downsides are that we cannot use the faster
// strconv.Quote here and that multi-line output is not
// supported. If developers know that a byte array is
// printable and they want multi-line output, they can
// convert the value to string before logging it.
b.WriteByte('=')
b.WriteString(fmt.Sprintf("%+q", v))
default:
f.formatAny(b, v)
}
}

View File

@@ -0,0 +1,155 @@
//go:build go1.21
// +build go1.21
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package serialize
import (
"bytes"
"fmt"
"log/slog"
"strconv"
"github.com/go-logr/logr"
)
// KVFormat serializes one key/value pair into the provided buffer.
// A space gets inserted before the pair.
func (f Formatter) KVFormat(b *bytes.Buffer, k, v interface{}) {
// This is the version without slog support. Must be kept in sync with
// the version in keyvalues_slog.go.
b.WriteByte(' ')
// Keys are assumed to be well-formed according to
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments
// for the sake of performance. Keys with spaces,
// special characters, etc. will break parsing.
if sK, ok := k.(string); ok {
// Avoid one allocation when the key is a string, which
// normally it should be.
b.WriteString(sK)
} else {
b.WriteString(fmt.Sprintf("%s", k))
}
// The type checks are sorted so that more frequently used ones
// come first because that is then faster in the common
// cases. In Kubernetes, ObjectRef (a Stringer) is more common
// than plain strings
// (https://github.com/kubernetes/kubernetes/pull/106594#issuecomment-975526235).
//
// slog.LogValuer does not need to be handled here because the handler will
// already have resolved such special values to the final value for logging.
switch v := v.(type) {
case textWriter:
writeTextWriterValue(b, v)
case slog.Value:
// This must come before fmt.Stringer because slog.Value implements
// fmt.Stringer, but does not produce the output that we want.
b.WriteByte('=')
generateJSON(b, v)
case fmt.Stringer:
writeStringValue(b, StringerToString(v))
case string:
writeStringValue(b, v)
case error:
writeStringValue(b, ErrorToString(v))
case logr.Marshaler:
value := MarshalerToValue(v)
// A marshaler that returns a string is useful for
// delayed formatting of complex values. We treat this
// case like a normal string. This is useful for
// multi-line support.
//
// We could do this by recursively formatting a value,
// but that comes with the risk of infinite recursion
// if a marshaler returns itself. Instead we call it
// only once and rely on it returning the intended
// value directly.
switch value := value.(type) {
case string:
writeStringValue(b, value)
default:
f.formatAny(b, value)
}
case slog.LogValuer:
value := slog.AnyValue(v).Resolve()
if value.Kind() == slog.KindString {
writeStringValue(b, value.String())
} else {
b.WriteByte('=')
generateJSON(b, value)
}
case []byte:
// In https://github.com/kubernetes/klog/pull/237 it was decided
// to format byte slices with "%+q". The advantages of that are:
// - readable output if the bytes happen to be printable
// - non-printable bytes get represented as unicode escape
// sequences (\uxxxx)
//
// The downsides are that we cannot use the faster
// strconv.Quote here and that multi-line output is not
// supported. If developers know that a byte array is
// printable and they want multi-line output, they can
// convert the value to string before logging it.
b.WriteByte('=')
b.WriteString(fmt.Sprintf("%+q", v))
default:
f.formatAny(b, v)
}
}
// generateJSON has the same preference for plain strings as KVFormat.
// In contrast to KVFormat it always produces valid JSON with no line breaks.
func generateJSON(b *bytes.Buffer, v interface{}) {
switch v := v.(type) {
case slog.Value:
switch v.Kind() {
case slog.KindGroup:
// Format as a JSON group. We must not involve f.AnyToStringHook (if there is any),
// because there is no guarantee that it produces valid JSON.
b.WriteByte('{')
for i, attr := range v.Group() {
if i > 0 {
b.WriteByte(',')
}
b.WriteString(strconv.Quote(attr.Key))
b.WriteByte(':')
generateJSON(b, attr.Value)
}
b.WriteByte('}')
case slog.KindLogValuer:
generateJSON(b, v.Resolve())
default:
// Peel off the slog.Value wrapper and format the actual value.
generateJSON(b, v.Any())
}
case fmt.Stringer:
b.WriteString(strconv.Quote(StringerToString(v)))
case logr.Marshaler:
generateJSON(b, MarshalerToValue(v))
case slog.LogValuer:
generateJSON(b, slog.AnyValue(v).Resolve().Any())
case string:
b.WriteString(strconv.Quote(v))
case error:
b.WriteString(strconv.Quote(v.Error()))
default:
formatAsJSON(b, v)
}
}

View File

@@ -0,0 +1,96 @@
//go:build go1.21
// +build go1.21
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package sloghandler
import (
"context"
"log/slog"
"runtime"
"strings"
"time"
"k8s.io/klog/v2/internal/severity"
)
func Handle(_ context.Context, record slog.Record, groups string, printWithInfos func(file string, line int, now time.Time, err error, s severity.Severity, msg string, kvList []interface{})) error {
now := record.Time
if now.IsZero() {
// This format doesn't support printing entries without a time.
now = time.Now()
}
// slog has numeric severity levels, with 0 as default "info", negative for debugging, and
// positive with some pre-defined levels for more important. Those ranges get mapped to
// the corresponding klog levels where possible, with "info" the default that is used
// also for negative debug levels.
level := record.Level
s := severity.InfoLog
switch {
case level >= slog.LevelError:
s = severity.ErrorLog
case level >= slog.LevelWarn:
s = severity.WarningLog
}
var file string
var line int
if record.PC != 0 {
// Same as https://cs.opensource.google/go/x/exp/+/642cacee:slog/record.go;drc=642cacee5cc05231f45555a333d07f1005ffc287;l=70
fs := runtime.CallersFrames([]uintptr{record.PC})
f, _ := fs.Next()
if f.File != "" {
file = f.File
if slash := strings.LastIndex(file, "/"); slash >= 0 {
file = file[slash+1:]
}
line = f.Line
}
} else {
file = "???"
line = 1
}
kvList := make([]interface{}, 0, 2*record.NumAttrs())
record.Attrs(func(attr slog.Attr) bool {
kvList = appendAttr(groups, kvList, attr)
return true
})
printWithInfos(file, line, now, nil, s, record.Message, kvList)
return nil
}
func Attrs2KVList(groups string, attrs []slog.Attr) []interface{} {
kvList := make([]interface{}, 0, 2*len(attrs))
for _, attr := range attrs {
kvList = appendAttr(groups, kvList, attr)
}
return kvList
}
func appendAttr(groups string, kvList []interface{}, attr slog.Attr) []interface{} {
var key string
if groups != "" {
key = groups + "." + attr.Key
} else {
key = attr.Key
}
return append(kvList, key, attr.Value)
}

View File

@@ -178,14 +178,14 @@ func (ks kobjSlice) process() (objs []interface{}, err string) {
return objectRefs, ""
}
var nilToken = []byte("<nil>")
var nilToken = []byte("null")
func (ks kobjSlice) WriteText(out *bytes.Buffer) {
s := reflect.ValueOf(ks.arg)
switch s.Kind() {
case reflect.Invalid:
// nil parameter, print as empty slice.
out.WriteString("[]")
// nil parameter, print as null.
out.Write(nilToken)
return
case reflect.Slice:
// Okay, handle below.
@@ -197,15 +197,15 @@ func (ks kobjSlice) WriteText(out *bytes.Buffer) {
defer out.Write([]byte{']'})
for i := 0; i < s.Len(); i++ {
if i > 0 {
out.Write([]byte{' '})
out.Write([]byte{','})
}
item := s.Index(i).Interface()
if item == nil {
out.Write(nilToken)
} else if v, ok := item.(KMetadata); ok {
KObj(v).writeUnquoted(out)
KObj(v).WriteText(out)
} else {
fmt.Fprintf(out, "<KObjSlice needs a slice of values implementing KMetadata, got type %T>", item)
fmt.Fprintf(out, `"<KObjSlice needs a slice of values implementing KMetadata, got type %T>"`, item)
return
}
}

39
vendor/k8s.io/klog/v2/k8s_references_slog.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
//go:build go1.21
// +build go1.21
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package klog
import (
"log/slog"
)
func (ref ObjectRef) LogValue() slog.Value {
if ref.Namespace != "" {
return slog.GroupValue(slog.String("name", ref.Name), slog.String("namespace", ref.Namespace))
}
return slog.GroupValue(slog.String("name", ref.Name))
}
var _ slog.LogValuer = ObjectRef{}
func (ks kobjSlice) LogValue() slog.Value {
return slog.AnyValue(ks.MarshalLog())
}
var _ slog.LogValuer = kobjSlice{}

176
vendor/k8s.io/klog/v2/klog.go generated vendored
View File

@@ -91,8 +91,6 @@ import (
"sync/atomic"
"time"
"github.com/go-logr/logr"
"k8s.io/klog/v2/internal/buffer"
"k8s.io/klog/v2/internal/clock"
"k8s.io/klog/v2/internal/dbg"
@@ -417,7 +415,7 @@ func init() {
logging.stderrThreshold = severityValue{
Severity: severity.ErrorLog, // Default stderrThreshold is ERROR.
}
commandLine.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=false)")
commandLine.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=true)")
commandLine.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging")
commandLine.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace")
@@ -453,7 +451,7 @@ type settings struct {
// logger is the global Logger chosen by users of klog, nil if
// none is available.
logger *Logger
logger *logWriter
// loggerOptions contains the options that were supplied for
// globalLogger.
@@ -520,11 +518,14 @@ type settings struct {
func (s settings) deepCopy() settings {
// vmodule is a slice and would be shared, so we have copy it.
filter := make([]modulePat, len(s.vmodule.filter))
for i := range s.vmodule.filter {
filter[i] = s.vmodule.filter[i]
}
copy(filter, s.vmodule.filter)
s.vmodule.filter = filter
if s.logger != nil {
logger := *s.logger
s.logger = &logger
}
return s
}
@@ -654,29 +655,33 @@ func (l *loggingT) header(s severity.Severity, depth int) (*buffer.Buffer, strin
}
}
}
return l.formatHeader(s, file, line), file, line
return l.formatHeader(s, file, line, timeNow()), file, line
}
// formatHeader formats a log header using the provided file name and line number.
func (l *loggingT) formatHeader(s severity.Severity, file string, line int) *buffer.Buffer {
func (l *loggingT) formatHeader(s severity.Severity, file string, line int, now time.Time) *buffer.Buffer {
buf := buffer.GetBuffer()
if l.skipHeaders {
return buf
}
now := timeNow()
buf.FormatHeader(s, file, line, now)
return buf
}
func (l *loggingT) println(s severity.Severity, logger *logr.Logger, filter LogFilter, args ...interface{}) {
func (l *loggingT) println(s severity.Severity, logger *logWriter, filter LogFilter, args ...interface{}) {
l.printlnDepth(s, logger, filter, 1, args...)
}
func (l *loggingT) printlnDepth(s severity.Severity, logger *logr.Logger, filter LogFilter, depth int, args ...interface{}) {
func (l *loggingT) printlnDepth(s severity.Severity, logger *logWriter, filter LogFilter, depth int, args ...interface{}) {
if false {
_ = fmt.Sprintln(args...) // cause vet to treat this function like fmt.Println
}
buf, file, line := l.header(s, depth)
// if logger is set, we clear the generated header as we rely on the backing
// logger implementation to print headers
if logger != nil {
// If a logger is set and doesn't support writing a formatted buffer,
// we clear the generated header as we rely on the backing
// logger implementation to print headers.
if logger != nil && logger.writeKlogBuffer == nil {
buffer.PutBuffer(buf)
buf = buffer.GetBuffer()
}
@@ -687,15 +692,24 @@ func (l *loggingT) printlnDepth(s severity.Severity, logger *logr.Logger, filter
l.output(s, logger, buf, depth, file, line, false)
}
func (l *loggingT) print(s severity.Severity, logger *logr.Logger, filter LogFilter, args ...interface{}) {
func (l *loggingT) print(s severity.Severity, logger *logWriter, filter LogFilter, args ...interface{}) {
l.printDepth(s, logger, filter, 1, args...)
}
func (l *loggingT) printDepth(s severity.Severity, logger *logr.Logger, filter LogFilter, depth int, args ...interface{}) {
func (l *loggingT) printDepth(s severity.Severity, logger *logWriter, filter LogFilter, depth int, args ...interface{}) {
if false {
_ = fmt.Sprint(args...) // // cause vet to treat this function like fmt.Print
}
buf, file, line := l.header(s, depth)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logger != nil {
l.printWithInfos(buf, file, line, s, logger, filter, depth+1, args...)
}
func (l *loggingT) printWithInfos(buf *buffer.Buffer, file string, line int, s severity.Severity, logger *logWriter, filter LogFilter, depth int, args ...interface{}) {
// If a logger is set and doesn't support writing a formatted buffer,
// we clear the generated header as we rely on the backing
// logger implementation to print headers.
if logger != nil && logger.writeKlogBuffer == nil {
buffer.PutBuffer(buf)
buf = buffer.GetBuffer()
}
@@ -709,15 +723,20 @@ func (l *loggingT) printDepth(s severity.Severity, logger *logr.Logger, filter L
l.output(s, logger, buf, depth, file, line, false)
}
func (l *loggingT) printf(s severity.Severity, logger *logr.Logger, filter LogFilter, format string, args ...interface{}) {
func (l *loggingT) printf(s severity.Severity, logger *logWriter, filter LogFilter, format string, args ...interface{}) {
l.printfDepth(s, logger, filter, 1, format, args...)
}
func (l *loggingT) printfDepth(s severity.Severity, logger *logr.Logger, filter LogFilter, depth int, format string, args ...interface{}) {
func (l *loggingT) printfDepth(s severity.Severity, logger *logWriter, filter LogFilter, depth int, format string, args ...interface{}) {
if false {
_ = fmt.Sprintf(format, args...) // cause vet to treat this function like fmt.Printf
}
buf, file, line := l.header(s, depth)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logger != nil {
// If a logger is set and doesn't support writing a formatted buffer,
// we clear the generated header as we rely on the backing
// logger implementation to print headers.
if logger != nil && logger.writeKlogBuffer == nil {
buffer.PutBuffer(buf)
buf = buffer.GetBuffer()
}
@@ -734,11 +753,12 @@ func (l *loggingT) printfDepth(s severity.Severity, logger *logr.Logger, filter
// printWithFileLine behaves like print but uses the provided file and line number. If
// alsoLogToStderr is true, the log message always appears on standard error; it
// will also appear in the log file unless --logtostderr is set.
func (l *loggingT) printWithFileLine(s severity.Severity, logger *logr.Logger, filter LogFilter, file string, line int, alsoToStderr bool, args ...interface{}) {
buf := l.formatHeader(s, file, line)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logger != nil {
func (l *loggingT) printWithFileLine(s severity.Severity, logger *logWriter, filter LogFilter, file string, line int, alsoToStderr bool, args ...interface{}) {
buf := l.formatHeader(s, file, line, timeNow())
// If a logger is set and doesn't support writing a formatted buffer,
// we clear the generated header as we rely on the backing
// logger implementation to print headers.
if logger != nil && logger.writeKlogBuffer == nil {
buffer.PutBuffer(buf)
buf = buffer.GetBuffer()
}
@@ -752,8 +772,8 @@ func (l *loggingT) printWithFileLine(s severity.Severity, logger *logr.Logger, f
l.output(s, logger, buf, 2 /* depth */, file, line, alsoToStderr)
}
// if loggr is specified, will call loggr.Error, otherwise output with logging module.
func (l *loggingT) errorS(err error, logger *logr.Logger, filter LogFilter, depth int, msg string, keysAndValues ...interface{}) {
// if logger is specified, will call logger.Error, otherwise output with logging module.
func (l *loggingT) errorS(err error, logger *logWriter, filter LogFilter, depth int, msg string, keysAndValues ...interface{}) {
if filter != nil {
msg, keysAndValues = filter.FilterS(msg, keysAndValues)
}
@@ -764,8 +784,8 @@ func (l *loggingT) errorS(err error, logger *logr.Logger, filter LogFilter, dept
l.printS(err, severity.ErrorLog, depth+1, msg, keysAndValues...)
}
// if loggr is specified, will call loggr.Info, otherwise output with logging module.
func (l *loggingT) infoS(logger *logr.Logger, filter LogFilter, depth int, msg string, keysAndValues ...interface{}) {
// if logger is specified, will call logger.Info, otherwise output with logging module.
func (l *loggingT) infoS(logger *logWriter, filter LogFilter, depth int, msg string, keysAndValues ...interface{}) {
if filter != nil {
msg, keysAndValues = filter.FilterS(msg, keysAndValues)
}
@@ -776,7 +796,7 @@ func (l *loggingT) infoS(logger *logr.Logger, filter LogFilter, depth int, msg s
l.printS(nil, severity.InfoLog, depth+1, msg, keysAndValues...)
}
// printS is called from infoS and errorS if loggr is not specified.
// printS is called from infoS and errorS if logger is not specified.
// set log severity by s
func (l *loggingT) printS(err error, s severity.Severity, depth int, msg string, keysAndValues ...interface{}) {
// Only create a new buffer if we don't have one cached.
@@ -789,7 +809,7 @@ func (l *loggingT) printS(err error, s severity.Severity, depth int, msg string,
serialize.KVListFormat(&b.Buffer, "err", err)
}
serialize.KVListFormat(&b.Buffer, keysAndValues...)
l.printDepth(s, logging.logger, nil, depth+1, &b.Buffer)
l.printDepth(s, nil, nil, depth+1, &b.Buffer)
// Make the buffer available for reuse.
buffer.PutBuffer(b)
}
@@ -846,7 +866,7 @@ func LogToStderr(stderr bool) {
}
// output writes the data to the log files and releases the buffer.
func (l *loggingT) output(s severity.Severity, log *logr.Logger, buf *buffer.Buffer, depth int, file string, line int, alsoToStderr bool) {
func (l *loggingT) output(s severity.Severity, logger *logWriter, buf *buffer.Buffer, depth int, file string, line int, alsoToStderr bool) {
var isLocked = true
l.mu.Lock()
defer func() {
@@ -862,13 +882,20 @@ func (l *loggingT) output(s severity.Severity, log *logr.Logger, buf *buffer.Buf
}
}
data := buf.Bytes()
if log != nil {
// TODO: set 'severity' and caller information as structured log info
// keysAndValues := []interface{}{"severity", severityName[s], "file", file, "line", line}
if s == severity.ErrorLog {
logging.logger.WithCallDepth(depth+3).Error(nil, string(data))
if logger != nil {
if logger.writeKlogBuffer != nil {
logger.writeKlogBuffer(data)
} else {
log.WithCallDepth(depth + 3).Info(string(data))
if len(data) > 0 && data[len(data)-1] == '\n' {
data = data[:len(data)-1]
}
// TODO: set 'severity' and caller information as structured log info
// keysAndValues := []interface{}{"severity", severityName[s], "file", file, "line", line}
if s == severity.ErrorLog {
logger.WithCallDepth(depth+3).Error(nil, string(data))
} else {
logger.WithCallDepth(depth + 3).Info(string(data))
}
}
} else if l.toStderr {
os.Stderr.Write(data)
@@ -886,7 +913,7 @@ func (l *loggingT) output(s severity.Severity, log *logr.Logger, buf *buffer.Buf
l.exit(err)
}
}
l.file[severity.InfoLog].Write(data)
_, _ = l.file[severity.InfoLog].Write(data)
} else {
if l.file[s] == nil {
if err := l.createFiles(s); err != nil {
@@ -896,20 +923,20 @@ func (l *loggingT) output(s severity.Severity, log *logr.Logger, buf *buffer.Buf
}
if l.oneOutput {
l.file[s].Write(data)
_, _ = l.file[s].Write(data)
} else {
switch s {
case severity.FatalLog:
l.file[severity.FatalLog].Write(data)
_, _ = l.file[severity.FatalLog].Write(data)
fallthrough
case severity.ErrorLog:
l.file[severity.ErrorLog].Write(data)
_, _ = l.file[severity.ErrorLog].Write(data)
fallthrough
case severity.WarningLog:
l.file[severity.WarningLog].Write(data)
_, _ = l.file[severity.WarningLog].Write(data)
fallthrough
case severity.InfoLog:
l.file[severity.InfoLog].Write(data)
_, _ = l.file[severity.InfoLog].Write(data)
}
}
}
@@ -935,7 +962,7 @@ func (l *loggingT) output(s severity.Severity, log *logr.Logger, buf *buffer.Buf
logExitFunc = func(error) {} // If we get a write error, we'll still exit below.
for log := severity.FatalLog; log >= severity.InfoLog; log-- {
if f := l.file[log]; f != nil { // Can be nil if -logtostderr is set.
f.Write(trace)
_, _ = f.Write(trace)
}
}
l.mu.Unlock()
@@ -1091,7 +1118,7 @@ const flushInterval = 5 * time.Second
// flushDaemon periodically flushes the log file buffers.
type flushDaemon struct {
mu sync.Mutex
clock clock.WithTicker
clock clock.Clock
flush func()
stopC chan struct{}
stopDone chan struct{}
@@ -1099,7 +1126,7 @@ type flushDaemon struct {
// newFlushDaemon returns a new flushDaemon. If the passed clock is nil, a
// clock.RealClock is used.
func newFlushDaemon(flush func(), tickClock clock.WithTicker) *flushDaemon {
func newFlushDaemon(flush func(), tickClock clock.Clock) *flushDaemon {
if tickClock == nil {
tickClock = clock.RealClock{}
}
@@ -1190,8 +1217,8 @@ func (l *loggingT) flushAll() {
for s := severity.FatalLog; s >= severity.InfoLog; s-- {
file := l.file[s]
if file != nil {
file.Flush() // ignore error
file.Sync() // ignore error
_ = file.Flush() // ignore error
_ = file.Sync() // ignore error
}
}
if logging.loggerOptions.flush != nil {
@@ -1217,6 +1244,19 @@ func CopyStandardLogTo(name string) {
stdLog.SetOutput(logBridge(sev))
}
// NewStandardLogger returns a Logger that writes to the klog logs for the
// named and lower severities.
//
// Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not
// recognized, NewStandardLogger panics.
func NewStandardLogger(name string) *stdLog.Logger {
sev, ok := severity.ByName(name)
if !ok {
panic(fmt.Sprintf("klog.NewStandardLogger(%q): unknown severity", name))
}
return stdLog.New(logBridge(sev), "", stdLog.Lshortfile)
}
// logBridge provides the Write method that enables CopyStandardLogTo to connect
// Go's standard logs to the logs provided by this package.
type logBridge severity.Severity
@@ -1257,9 +1297,7 @@ func (l *loggingT) setV(pc uintptr) Level {
fn := runtime.FuncForPC(pc)
file, _ := fn.FileLine(pc)
// The file is something like /a/b/c/d.go. We want just the d.
if strings.HasSuffix(file, ".go") {
file = file[:len(file)-3]
}
file = strings.TrimSuffix(file, ".go")
if slash := strings.LastIndex(file, "/"); slash >= 0 {
file = file[slash+1:]
}
@@ -1277,7 +1315,7 @@ func (l *loggingT) setV(pc uintptr) Level {
// See the documentation of V for more information.
type Verbose struct {
enabled bool
logr *logr.Logger
logger *logWriter
}
func newVerbose(level Level, b bool) Verbose {
@@ -1285,7 +1323,7 @@ func newVerbose(level Level, b bool) Verbose {
return Verbose{b, nil}
}
v := logging.logger.V(int(level))
return Verbose{b, &v}
return Verbose{b, &logWriter{Logger: v, writeKlogBuffer: logging.loggerOptions.writeKlogBuffer}}
}
// V reports whether verbosity at the call site is at least the requested level.
@@ -1359,7 +1397,7 @@ func (v Verbose) Enabled() bool {
// See the documentation of V for usage.
func (v Verbose) Info(args ...interface{}) {
if v.enabled {
logging.print(severity.InfoLog, v.logr, logging.filter, args...)
logging.print(severity.InfoLog, v.logger, logging.filter, args...)
}
}
@@ -1367,7 +1405,7 @@ func (v Verbose) Info(args ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) InfoDepth(depth int, args ...interface{}) {
if v.enabled {
logging.printDepth(severity.InfoLog, v.logr, logging.filter, depth, args...)
logging.printDepth(severity.InfoLog, v.logger, logging.filter, depth, args...)
}
}
@@ -1375,7 +1413,7 @@ func (v Verbose) InfoDepth(depth int, args ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) Infoln(args ...interface{}) {
if v.enabled {
logging.println(severity.InfoLog, v.logr, logging.filter, args...)
logging.println(severity.InfoLog, v.logger, logging.filter, args...)
}
}
@@ -1383,7 +1421,7 @@ func (v Verbose) Infoln(args ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) InfolnDepth(depth int, args ...interface{}) {
if v.enabled {
logging.printlnDepth(severity.InfoLog, v.logr, logging.filter, depth, args...)
logging.printlnDepth(severity.InfoLog, v.logger, logging.filter, depth, args...)
}
}
@@ -1391,7 +1429,7 @@ func (v Verbose) InfolnDepth(depth int, args ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) Infof(format string, args ...interface{}) {
if v.enabled {
logging.printf(severity.InfoLog, v.logr, logging.filter, format, args...)
logging.printf(severity.InfoLog, v.logger, logging.filter, format, args...)
}
}
@@ -1399,7 +1437,7 @@ func (v Verbose) Infof(format string, args ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) InfofDepth(depth int, format string, args ...interface{}) {
if v.enabled {
logging.printfDepth(severity.InfoLog, v.logr, logging.filter, depth, format, args...)
logging.printfDepth(severity.InfoLog, v.logger, logging.filter, depth, format, args...)
}
}
@@ -1407,7 +1445,7 @@ func (v Verbose) InfofDepth(depth int, format string, args ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) InfoS(msg string, keysAndValues ...interface{}) {
if v.enabled {
logging.infoS(v.logr, logging.filter, 0, msg, keysAndValues...)
logging.infoS(v.logger, logging.filter, 0, msg, keysAndValues...)
}
}
@@ -1421,14 +1459,14 @@ func InfoSDepth(depth int, msg string, keysAndValues ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) InfoSDepth(depth int, msg string, keysAndValues ...interface{}) {
if v.enabled {
logging.infoS(v.logr, logging.filter, depth, msg, keysAndValues...)
logging.infoS(v.logger, logging.filter, depth, msg, keysAndValues...)
}
}
// Deprecated: Use ErrorS instead.
func (v Verbose) Error(err error, msg string, args ...interface{}) {
if v.enabled {
logging.errorS(err, v.logr, logging.filter, 0, msg, args...)
logging.errorS(err, v.logger, logging.filter, 0, msg, args...)
}
}
@@ -1436,7 +1474,7 @@ func (v Verbose) Error(err error, msg string, args ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) ErrorS(err error, msg string, keysAndValues ...interface{}) {
if v.enabled {
logging.errorS(err, v.logr, logging.filter, 0, msg, keysAndValues...)
logging.errorS(err, v.logger, logging.filter, 0, msg, keysAndValues...)
}
}

4
vendor/k8s.io/klog/v2/klog_file.go generated vendored
View File

@@ -109,8 +109,8 @@ func create(tag string, t time.Time, startup bool) (f *os.File, filename string,
f, err := openOrCreate(fname, startup)
if err == nil {
symlink := filepath.Join(dir, link)
os.Remove(symlink) // ignore err
os.Symlink(name, symlink) // ignore err
_ = os.Remove(symlink) // ignore err
_ = os.Symlink(name, symlink) // ignore err
return f, fname, nil
}
lastErr = err

46
vendor/k8s.io/klog/v2/klogr.go generated vendored
View File

@@ -22,6 +22,11 @@ import (
"k8s.io/klog/v2/internal/serialize"
)
const (
// nameKey is used to log the `WithName` values as an additional attribute.
nameKey = "logger"
)
// NewKlogr returns a logger that is functionally identical to
// klogr.NewWithOptions(klogr.FormatKlog), i.e. it passes through to klog. The
// difference is that it uses a simpler implementation.
@@ -32,10 +37,15 @@ func NewKlogr() Logger {
// klogger is a subset of klogr/klogr.go. It had to be copied to break an
// import cycle (klogr wants to use klog, and klog wants to use klogr).
type klogger struct {
level int
callDepth int
prefix string
values []interface{}
// hasPrefix is true if the first entry in values is the special
// nameKey key/value. Such an entry gets added and later updated in
// WithName.
hasPrefix bool
values []interface{}
groups string
}
func (l *klogger) Init(info logr.RuntimeInfo) {
@@ -44,34 +54,40 @@ func (l *klogger) Init(info logr.RuntimeInfo) {
func (l *klogger) Info(level int, msg string, kvList ...interface{}) {
merged := serialize.MergeKVs(l.values, kvList)
if l.prefix != "" {
msg = l.prefix + ": " + msg
}
// Skip this function.
VDepth(l.callDepth+1, Level(level)).InfoSDepth(l.callDepth+1, msg, merged...)
}
func (l *klogger) Enabled(level int) bool {
// Skip this function and logr.Logger.Info where Enabled is called.
return VDepth(l.callDepth+2, Level(level)).Enabled()
return VDepth(l.callDepth+1, Level(level)).Enabled()
}
func (l *klogger) Error(err error, msg string, kvList ...interface{}) {
merged := serialize.MergeKVs(l.values, kvList)
if l.prefix != "" {
msg = l.prefix + ": " + msg
}
ErrorSDepth(l.callDepth+1, err, msg, merged...)
}
// WithName returns a new logr.Logger with the specified name appended. klogr
// uses '/' characters to separate name elements. Callers should not pass '/'
// uses '.' characters to separate name elements. Callers should not pass '.'
// in the provided name string, but this library does not actually enforce that.
func (l klogger) WithName(name string) logr.LogSink {
if len(l.prefix) > 0 {
l.prefix = l.prefix + "/"
if l.hasPrefix {
// Copy slice and modify value. No length checks and type
// assertions are needed because hasPrefix is only true if the
// first two elements exist and are key/value strings.
v := make([]interface{}, 0, len(l.values))
v = append(v, l.values...)
prefix, _ := v[1].(string)
v[1] = prefix + "." + name
l.values = v
} else {
// Preprend new key/value pair.
v := make([]interface{}, 0, 2+len(l.values))
v = append(v, nameKey, name)
v = append(v, l.values...)
l.values = v
l.hasPrefix = true
}
l.prefix += name
return &l
}

96
vendor/k8s.io/klog/v2/klogr_slog.go generated vendored Normal file
View File

@@ -0,0 +1,96 @@
//go:build go1.21
// +build go1.21
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package klog
import (
"context"
"log/slog"
"strconv"
"time"
"github.com/go-logr/logr/slogr"
"k8s.io/klog/v2/internal/buffer"
"k8s.io/klog/v2/internal/serialize"
"k8s.io/klog/v2/internal/severity"
"k8s.io/klog/v2/internal/sloghandler"
)
func (l *klogger) Handle(ctx context.Context, record slog.Record) error {
if logging.logger != nil {
if slogSink, ok := logging.logger.GetSink().(slogr.SlogSink); ok {
// Let that logger do the work.
return slogSink.Handle(ctx, record)
}
}
return sloghandler.Handle(ctx, record, l.groups, slogOutput)
}
// slogOutput corresponds to several different functions in klog.go.
// It goes through some of the same checks and formatting steps before
// it ultimately converges by calling logging.printWithInfos.
func slogOutput(file string, line int, now time.Time, err error, s severity.Severity, msg string, kvList []interface{}) {
// See infoS.
if logging.logger != nil {
// Taking this path happens when klog has a logger installed
// as backend which doesn't support slog. Not good, we have to
// guess about the call depth and drop the actual location.
logger := logging.logger.WithCallDepth(2)
if s > severity.ErrorLog {
logger.Error(err, msg, kvList...)
} else {
logger.Info(msg, kvList...)
}
return
}
// See printS.
b := buffer.GetBuffer()
b.WriteString(strconv.Quote(msg))
if err != nil {
serialize.KVListFormat(&b.Buffer, "err", err)
}
serialize.KVListFormat(&b.Buffer, kvList...)
// See print + header.
buf := logging.formatHeader(s, file, line, now)
logging.printWithInfos(buf, file, line, s, nil, nil, 0, &b.Buffer)
buffer.PutBuffer(b)
}
func (l *klogger) WithAttrs(attrs []slog.Attr) slogr.SlogSink {
clone := *l
clone.values = serialize.WithValues(l.values, sloghandler.Attrs2KVList(l.groups, attrs))
return &clone
}
func (l *klogger) WithGroup(name string) slogr.SlogSink {
clone := *l
if clone.groups != "" {
clone.groups += "." + name
} else {
clone.groups = name
}
return &clone
}
var _ slogr.SlogSink = &klogger{}