55 "fmt"
66 "io"
77 "os"
8+ "path"
9+ "runtime"
810 "strconv"
911 "strings"
1012 "sync/atomic"
@@ -35,11 +37,13 @@ func NewWithOptions(opts Options) *Logger {
3537 panic ("logger was supplied with nil writer" )
3638 }
3739 l := & Logger {
38- w : opts .Writer ,
39- humanize : opts .Humanize ,
40- tsFormat : opts .TimestampFormat ,
41- nameDelim : opts .NameDelim ,
42- colorize : opts .Colorize && opts .Humanize ,
40+ w : opts .Writer ,
41+ humanize : opts .Humanize ,
42+ tsFormat : opts .TimestampFormat ,
43+ nameDelim : opts .NameDelim ,
44+ colorize : opts .Colorize && opts .Humanize ,
45+ addCaller : opts .AddCaller ,
46+ callerSkip : opts .CallerSkip ,
4347 }
4448 return l
4549}
@@ -71,21 +75,30 @@ type Options struct {
7175
7276 // NameDelim is the delimiter character used when appending names of loggers.
7377 NameDelim string
78+
79+ // AddCaller indicates that log messages should include the file and line number of the caller of the logger.
80+ AddCaller bool
81+
82+ // CallerSkip adds frames to skip when determing the caller of the logger. Useful when the logger is wrapped
83+ // by another logger.
84+ CallerSkip int
7485}
7586
7687var _ logr.Logger = (* Logger )(nil )
7788
7889// Logger is a logger that writes messages in the logfmt style.
7990// See https://www.brandur.org/logfmt for more information.
8091type Logger struct {
81- w io.Writer
82- level int
83- name string
84- values string
85- humanize bool
86- tsFormat string
87- nameDelim string
88- colorize bool
92+ w io.Writer
93+ level int
94+ name string
95+ values string
96+ humanize bool
97+ tsFormat string
98+ nameDelim string
99+ colorize bool
100+ addCaller bool
101+ callerSkip int
89102}
90103
91104// Enabled repoorts whether this Logger is enabled with respect to the current global log level.
@@ -125,6 +138,12 @@ func (l *Logger) write(humanprefix, msg string, values string, extras ...interfa
125138 b .WriteString ("=" )
126139 b .WriteString (l .name )
127140 }
141+ if l .addCaller {
142+ b .WriteRune (' ' )
143+ b .WriteString (l .key ("caller" ))
144+ b .WriteString ("=" )
145+ b .WriteString (l .caller (2 ))
146+ }
128147 } else {
129148 b .WriteString ("level=" )
130149 b .WriteString (strconv .Itoa (l .level ))
@@ -141,11 +160,17 @@ func (l *Logger) write(humanprefix, msg string, values string, extras ...interfa
141160 b .WriteString ("ts=" )
142161 b .WriteString (quote (time .Now ().UTC ().Format (l .tsFormat )))
143162 }
163+ if l .addCaller {
164+ b .WriteRune (' ' )
165+ b .WriteString ("caller=" )
166+ b .WriteString (l .caller (2 ))
167+ }
144168 }
145169 if len (extras ) > 0 {
146170 b .WriteRune (' ' )
147171 b .WriteString (l .flatten (extras ... ))
148172 }
173+
149174 if l .values != "" {
150175 b .WriteRune (' ' )
151176 b .WriteString (l .values )
@@ -158,6 +183,16 @@ func (l *Logger) write(humanprefix, msg string, values string, extras ...interfa
158183 l .w .Write (b .Bytes ())
159184}
160185
186+ func (l * Logger ) caller (skip int ) string {
187+ for i := 1 ; i < 3 ; i ++ {
188+ _ , file , line , ok := runtime .Caller (skip + l .callerSkip + i )
189+ if ok && file != "<autogenerated>" {
190+ return path .Base (file ) + ":" + strconv .Itoa (line )
191+ }
192+ }
193+ return "unknown"
194+ }
195+
161196// V returns a logger for a specific verbosity level, relative to this Logger.
162197func (l * Logger ) V (level int ) logr.Logger {
163198 l2 := * l
@@ -245,7 +280,7 @@ func stringify(v interface{}) string {
245280}
246281
247282func quote (s string ) string {
248- if strings .ContainsAny (s , " . " ) {
283+ if strings .ContainsAny (s , " " ) {
249284 return fmt .Sprintf ("%q" , s )
250285 }
251286 return s
0 commit comments