@@ -42,6 +42,8 @@ import (
4242// No serialization is provided by Logger, its log.Output responsibility to
4343// ensure goroutine-safety if necessary.
4444type Logger struct {
45+ Parent * Logger
46+
4547 Out Output
4648 Name string
4749 Debug bool
@@ -51,30 +53,37 @@ type Logger struct {
5153 Fields map [string ]interface {}
5254}
5355
54- func (l Logger ) Zap () * zap.Logger {
56+ func (l * Logger ) Zap () * zap.Logger {
5557 // TODO: Migrate to using zap natively.
5658 return zap .New (zapLogger {L : l })
5759}
5860
59- func (l Logger ) Debugf (format string , val ... interface {}) {
60- if ! l .Debug {
61+ func (l * Logger ) IsDebug () bool {
62+ if l .Parent == nil {
63+ return l .Debug
64+ }
65+ return l .Debug || l .Parent .IsDebug ()
66+ }
67+
68+ func (l * Logger ) Debugf (format string , val ... interface {}) {
69+ if ! l .IsDebug () {
6170 return
6271 }
6372 l .log (true , l .formatMsg (fmt .Sprintf (format , val ... ), nil ))
6473}
6574
66- func (l Logger ) Debugln (val ... interface {}) {
67- if ! l .Debug {
75+ func (l * Logger ) Debugln (val ... interface {}) {
76+ if ! l .IsDebug () {
6877 return
6978 }
7079 l .log (true , l .formatMsg (strings .TrimRight (fmt .Sprintln (val ... ), "\n " ), nil ))
7180}
7281
73- func (l Logger ) Printf (format string , val ... interface {}) {
82+ func (l * Logger ) Printf (format string , val ... interface {}) {
7483 l .log (false , l .formatMsg (fmt .Sprintf (format , val ... ), nil ))
7584}
7685
77- func (l Logger ) Println (val ... interface {}) {
86+ func (l * Logger ) Println (val ... interface {}) {
7887 l .log (false , l .formatMsg (strings .TrimRight (fmt .Sprintln (val ... ), "\n " ), nil ))
7988}
8089
@@ -87,13 +96,13 @@ func (l Logger) Println(val ...interface{}) {
8796// followed by corresponding values. That is, for example, []interface{"key",
8897// "value", "key2", "value2"}.
8998//
90- // If value in fields implements LogFormatter , it will be represented by the
99+ // If value in fields implements Formatter , it will be represented by the
91100// string returned by FormatLog method. Same goes for fmt.Stringer and error
92101// interfaces.
93102//
94103// Additionally, time.Time is written as a string in ISO 8601 format.
95104// time.Duration follows fmt.Stringer rule above.
96- func (l Logger ) Msg (msg string , fields ... interface {}) {
105+ func (l * Logger ) Msg (msg string , fields ... interface {}) {
97106 m := make (map [string ]interface {}, len (fields )/ 2 )
98107 fieldsToMap (fields , m )
99108 l .log (false , l .formatMsg (msg , m ))
@@ -112,7 +121,7 @@ func (l Logger) Msg(msg string, fields ...interface{}) {
112121// In the context of Error method, "msg" typically indicates the top-level
113122// context in which the error is *handled*. For example, if error leads to
114123// rejection of SMTP DATA command, msg will probably be "DATA error".
115- func (l Logger ) Error (msg string , err error , fields ... interface {}) {
124+ func (l * Logger ) Error (msg string , err error , fields ... interface {}) {
116125 if err == nil {
117126 return
118127 }
@@ -133,8 +142,8 @@ func (l Logger) Error(msg string, err error, fields ...interface{}) {
133142 l .log (false , l .formatMsg (msg , allFields ))
134143}
135144
136- func (l Logger ) DebugMsg (kind string , fields ... interface {}) {
137- if ! l .Debug {
145+ func (l * Logger ) DebugMsg (kind string , fields ... interface {}) {
146+ if ! l .IsDebug () {
138147 return
139148 }
140149 m := make (map [string ]interface {}, len (fields )/ 2 )
@@ -162,7 +171,7 @@ func fieldsToMap(fields []interface{}, out map[string]interface{}) {
162171 }
163172}
164173
165- func (l Logger ) formatMsg (msg string , fields map [string ]interface {}) string {
174+ func (l * Logger ) formatMsg (msg string , fields map [string ]interface {}) string {
166175 formatted := strings.Builder {}
167176
168177 formatted .WriteString (msg )
@@ -184,30 +193,31 @@ func (l Logger) formatMsg(msg string, fields map[string]interface{}) string {
184193 return formatted .String ()
185194}
186195
187- type LogFormatter interface {
196+ type Formatter interface {
188197 FormatLog () string
189198}
190199
191200// Write implements io.Writer, all bytes sent
192201// to it will be written as a separate log messages.
193202// No line-buffering is done.
194- func (l Logger ) Write (s []byte ) (int , error ) {
203+ func (l * Logger ) Write (s []byte ) (int , error ) {
204+ if ! l .IsDebug () {
205+ return len (s ), nil
206+ }
195207 l .log (false , strings .TrimRight (string (s ), "\n " ))
196208 return len (s ), nil
197209}
198210
199211// DebugWriter returns a writer that will act like Logger.Write
200212// but will use debug flag on messages. If Logger.Debug is false,
201213// Write method of returned object will be no-op.
202- func (l Logger ) DebugWriter () io.Writer {
203- if ! l .Debug {
204- return io .Discard
205- }
206- l .Debug = true
207- return & l
214+ func (l * Logger ) DebugWriter () io.Writer {
215+ l2 := l .Sublogger ("" )
216+ l2 .Debug = true
217+ return l2
208218}
209219
210- func (l Logger ) log (debug bool , s string ) {
220+ func (l * Logger ) log (debug bool , s string ) {
211221 if l .Name != "" {
212222 s = l .Name + ": " + s
213223 }
@@ -224,14 +234,15 @@ func (l Logger) log(debug bool, s string) {
224234 // Logging is disabled - do nothing.
225235}
226236
227- func (l Logger ) Sublogger (name string ) Logger {
228- if l .Name != "" {
237+ func (l * Logger ) Sublogger (name string ) * Logger {
238+ if l .Name != "" && name != "" {
229239 name = l .Name + "/" + name
230240 }
231- return Logger {
232- Out : l .Out ,
233- Name : name ,
234- Debug : l .Debug ,
241+ return & Logger {
242+ Parent : l ,
243+ Out : l .Out ,
244+ Name : name ,
245+ Debug : l .Debug ,
235246 }
236247}
237248
0 commit comments