11// package golog implements logging functions that log errors to stderr and
2- // debug messages to stdout. Trace logging is also supported. Trace logs go to
3- // stdout as well, but they are only written if the program is run with
4- // environment variable "TRACE=true"
2+ // debug messages to stdout. Trace logging is also supported.
3+ // Trace logs go to stdout as well, but they are only written if the program
4+ // is run with environment variable "TRACE=true".
5+ // A stack dump will be printed after the message if "PRINT_STACK=true".
56package golog
67
78import (
89 "bufio"
10+ "bytes"
911 "fmt"
1012 "io"
1113 "io/ioutil"
@@ -106,16 +108,20 @@ func LoggerFor(prefix string) Logger {
106108 l .traceOut = ioutil .Discard
107109 }
108110
111+ printStack := os .Getenv ("PRINT_STACK" )
112+ l .printStack , _ = strconv .ParseBool (printStack )
113+
109114 return l
110115}
111116
112117type logger struct {
113- prefix string
114- traceOn bool
115- traceOut io.Writer
116- outs atomic.Value
117- pc []uintptr
118- funcForPc * runtime.Func
118+ prefix string
119+ traceOn bool
120+ traceOut io.Writer
121+ printStack bool
122+ outs atomic.Value
123+ pc []uintptr
124+ funcForPc * runtime.Func
119125}
120126
121127// attaches the file and line number corresponding to
@@ -132,13 +138,19 @@ func (l *logger) print(out io.Writer, skipFrames int, severity string, arg inter
132138 if err != nil {
133139 errorOnLogging (err )
134140 }
141+ if l .printStack {
142+ l .doPrintStack ()
143+ }
135144}
136145
137146func (l * logger ) printf (out io.Writer , skipFrames int , severity string , message string , args ... interface {}) {
138147 _ , err := fmt .Fprintf (out , severity + " " + l .linePrefix (skipFrames )+ message + "\n " , args ... )
139148 if err != nil {
140149 errorOnLogging (err )
141150 }
151+ if l .printStack {
152+ l .doPrintStack ()
153+ }
142154}
143155
144156func (l * logger ) Debug (arg interface {}) {
@@ -232,6 +244,24 @@ func (l *logger) AsStdLogger() *log.Logger {
232244 return log .New (& errorWriter {l }, "" , 0 )
233245}
234246
247+ func (l * logger ) doPrintStack () {
248+ var b []byte
249+ buf := bytes .NewBuffer (b )
250+ for _ , pc := range l .pc {
251+ funcForPc := runtime .FuncForPC (pc )
252+ if funcForPc == nil {
253+ break
254+ }
255+ file , line := funcForPc .FileLine (pc )
256+ name := funcForPc .Name ()
257+ if strings .HasPrefix (name , "runtime." ) {
258+ break
259+ }
260+ fmt .Fprintf (buf , "\t %s\t %s: %d\n " , name , file , line )
261+ }
262+ buf .WriteTo (os .Stderr )
263+ }
264+
235265func errorOnLogging (err error ) {
236266 fmt .Fprintf (os .Stderr , "Unable to log: %v\n " , err )
237267}
0 commit comments