mirror of
https://github.com/coredns/coredns.git
synced 2026-10-09 12:05:22 -04:00
100 lines
2.5 KiB
Go
100 lines
2.5 KiB
Go
package kubernetes
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
|
|
clog "github.com/coredns/coredns/plugin/pkg/log"
|
|
|
|
"github.com/go-logr/logr"
|
|
)
|
|
|
|
// missingValue is what klog prints for a key without a value.
|
|
const missingValue = "(MISSING)"
|
|
|
|
// loggerAdapter is a simple wrapper around CoreDNS plugin logger made to implement logr.LogSink interface, which is used
|
|
// as part of klog library for logging in Kubernetes client. By using this adapter CoreDNS is able to log messages/errors from
|
|
// kubernetes client in a CoreDNS logging format
|
|
type loggerAdapter struct {
|
|
clog.P
|
|
values []any // always even-length, see WithValues
|
|
}
|
|
|
|
func (l *loggerAdapter) Init(_ logr.RuntimeInfo) {
|
|
}
|
|
|
|
func (l *loggerAdapter) Enabled(_ int) bool {
|
|
// verbosity is controlled inside klog library, we do not need to do anything here
|
|
return true
|
|
}
|
|
|
|
func (l *loggerAdapter) Info(_ int, msg string, keysAndValues ...any) {
|
|
l.P.Info(l.sprint(msg, nil, keysAndValues))
|
|
}
|
|
|
|
func (l *loggerAdapter) Error(err error, msg string, keysAndValues ...any) {
|
|
l.P.Error(l.sprint(msg, err, keysAndValues))
|
|
}
|
|
|
|
func (l *loggerAdapter) WithValues(keysAndValues ...any) logr.LogSink {
|
|
if len(keysAndValues) == 0 {
|
|
return l
|
|
}
|
|
clone := *l
|
|
clone.values = append(slices.Clip(l.values), keysAndValues...)
|
|
if len(clone.values)%2 != 0 {
|
|
// pad like klog does, so later pairs don't shift
|
|
clone.values = append(clone.values, missingValue)
|
|
}
|
|
return &clone
|
|
}
|
|
|
|
func (l *loggerAdapter) WithName(_ string) logr.LogSink {
|
|
return l
|
|
}
|
|
|
|
// sprint renders the message followed by the error (if any) and key/value pairs,
|
|
// since client-go puts most context (resource type, reflector name) in the latter.
|
|
// Duplicate keys are collapsed with the last value winning, as in klog.
|
|
func (l *loggerAdapter) sprint(msg string, err error, keysAndValues []any) string {
|
|
var b strings.Builder
|
|
b.WriteString(msg)
|
|
if err != nil {
|
|
b.WriteString(": ")
|
|
b.WriteString(err.Error())
|
|
}
|
|
kvs := keysAndValues
|
|
if len(l.values) > 0 {
|
|
kvs = append(slices.Clip(l.values), keysAndValues...)
|
|
}
|
|
for i := 0; i < len(kvs); i += 2 {
|
|
k := fmt.Sprint(kvs[i])
|
|
if hasLaterKey(kvs, i+2, k) {
|
|
continue
|
|
}
|
|
var v any = missingValue
|
|
if i+1 < len(kvs) {
|
|
v = kvs[i+1]
|
|
}
|
|
switch v := v.(type) {
|
|
case string:
|
|
fmt.Fprintf(&b, " %s=%q", k, v)
|
|
case error:
|
|
fmt.Fprintf(&b, " %s=%q", k, v.Error())
|
|
default:
|
|
fmt.Fprintf(&b, " %s=%v", k, v)
|
|
}
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func hasLaterKey(kvs []any, from int, key string) bool {
|
|
for j := from; j < len(kvs); j += 2 {
|
|
if fmt.Sprint(kvs[j]) == key {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|