1
17
18
19
20
21
22 package textlogger
23
24 import (
25 "runtime"
26 "strconv"
27 "strings"
28 "time"
29
30 "github.com/go-logr/logr"
31
32 "k8s.io/klog/v2/internal/buffer"
33 "k8s.io/klog/v2/internal/serialize"
34 "k8s.io/klog/v2/internal/severity"
35 "k8s.io/klog/v2/internal/verbosity"
36 )
37
38 var (
39
40 TimeNow = time.Now
41 )
42
43 const (
44
45 nameKey = "logger"
46 )
47
48
49
50
51
52 func NewLogger(c *Config) logr.Logger {
53 return logr.New(&tlogger{
54 values: nil,
55 config: c,
56 })
57 }
58
59 type tlogger struct {
60 callDepth int
61
62
63
64
65 hasPrefix bool
66
67 values []interface{}
68 groups string
69 config *Config
70 }
71
72 func (l *tlogger) Init(info logr.RuntimeInfo) {
73 l.callDepth = info.CallDepth
74 }
75
76 func (l *tlogger) WithCallDepth(depth int) logr.LogSink {
77 newLogger := *l
78 newLogger.callDepth += depth
79 return &newLogger
80 }
81
82 func (l *tlogger) Enabled(level int) bool {
83 return l.config.vstate.Enabled(verbosity.Level(level), 1+l.callDepth)
84 }
85
86 func (l *tlogger) Info(_ int, msg string, kvList ...interface{}) {
87 l.print(nil, severity.InfoLog, msg, kvList)
88 }
89
90 func (l *tlogger) Error(err error, msg string, kvList ...interface{}) {
91 l.print(err, severity.ErrorLog, msg, kvList)
92 }
93
94 func (l *tlogger) print(err error, s severity.Severity, msg string, kvList []interface{}) {
95
96
97 skip := l.callDepth + 2
98 file, line := l.config.co.unwind(skip)
99 if file == "" {
100 file = "???"
101 line = 1
102 } else if slash := strings.LastIndex(file, "/"); slash >= 0 {
103 file = file[slash+1:]
104 }
105 l.printWithInfos(file, line, time.Now(), err, s, msg, kvList)
106 }
107
108 func runtimeBacktrace(skip int) (string, int) {
109 _, file, line, ok := runtime.Caller(skip + 1)
110 if !ok {
111 return "", 0
112 }
113 return file, line
114 }
115
116 func (l *tlogger) printWithInfos(file string, line int, now time.Time, err error, s severity.Severity, msg string, kvList []interface{}) {
117
118 b := buffer.GetBuffer()
119 defer buffer.PutBuffer(b)
120
121
122 if l.config.co.fixedTime != nil {
123 now = *l.config.co.fixedTime
124 }
125 b.FormatHeader(s, file, line, now)
126
127
128
129
130 b.WriteString(strconv.Quote(msg))
131 if err != nil {
132 serialize.KVFormat(&b.Buffer, "err", err)
133 }
134 serialize.MergeAndFormatKVs(&b.Buffer, l.values, kvList)
135 if b.Len() == 0 || b.Bytes()[b.Len()-1] != '\n' {
136 b.WriteByte('\n')
137 }
138 _, _ = l.config.co.output.Write(b.Bytes())
139 }
140
141 func (l *tlogger) WriteKlogBuffer(data []byte) {
142 _, _ = l.config.co.output.Write(data)
143 }
144
145
146
147
148 func (l *tlogger) WithName(name string) logr.LogSink {
149 clone := *l
150 if l.hasPrefix {
151
152
153
154 v := make([]interface{}, 0, len(l.values))
155 v = append(v, l.values...)
156 prefix, _ := v[1].(string)
157 v[1] = prefix + "." + name
158 clone.values = v
159 } else {
160
161 v := make([]interface{}, 0, 2+len(l.values))
162 v = append(v, nameKey, name)
163 v = append(v, l.values...)
164 clone.values = v
165 clone.hasPrefix = true
166 }
167 return &clone
168 }
169
170 func (l *tlogger) WithValues(kvList ...interface{}) logr.LogSink {
171 clone := *l
172 clone.values = serialize.WithValues(l.values, kvList)
173 return &clone
174 }
175
176
177 type KlogBufferWriter interface {
178
179
180
181
182 WriteKlogBuffer([]byte)
183 }
184
185 var _ logr.LogSink = &tlogger{}
186 var _ logr.CallDepthLogSink = &tlogger{}
187 var _ KlogBufferWriter = &tlogger{}
188
View as plain text