Skip to content

Commit 3317291

Browse files
authoredAug 16, 2016
Merge pull request #4863 from getlantern/issue4803
Simplify golog and errors package by calling PrintStack directly
2 parents fec55ba + d78e584 commit 3317291

File tree

3 files changed

+32
-125
lines changed

3 files changed

+32
-125
lines changed
 

‎src/github.com/getlantern/errors/errors.go

+14-46
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ package errors
5959

6060
import (
6161
"bufio"
62-
"bytes"
6362
"crypto/tls"
6463
"crypto/x509"
6564
"encoding/hex"
@@ -105,8 +104,11 @@ type Error interface {
105104
// This can be useful when performing analytics on the error.
106105
ErrorClean() string
107106

108-
// MultiLinePrinter implements the interface golog.MultiLine
109-
MultiLinePrinter() func(buf *bytes.Buffer) bool
107+
// PrintStack prints the stacktrace when this Error is created, together
108+
// with the cause of this Error (if any), then the stacktrace when the
109+
// cause is created, and so on.
110+
// The output is an analogy of Java's stacktrace.
111+
PrintStack(w io.Writer, linePrefix string)
110112

111113
// Op attaches a hint of the operation triggers this Error. Many error types
112114
// returned by net and os package have Op pre-filled.
@@ -223,53 +225,19 @@ func (e *structured) Error() string {
223225
return e.data["error_text"].(string) + e.hiddenID
224226
}
225227

226-
func (e *structured) MultiLinePrinter() func(buf *bytes.Buffer) bool {
227-
first := true
228-
indent := false
228+
func (e *structured) PrintStack(w io.Writer, linePrefix string) {
229229
err := e
230-
stackPosition := 0
231-
switchedCause := false
232-
return func(buf *bytes.Buffer) bool {
233-
if indent {
234-
buf.WriteString(" ")
235-
}
236-
if first {
237-
buf.WriteString(e.Error())
238-
first = false
239-
indent = true
240-
return true
241-
}
242-
if switchedCause {
243-
fmt.Fprintf(buf, "Caused by: %v", err)
244-
if err.callStack != nil && len(err.callStack) > 0 {
245-
switchedCause = false
246-
indent = true
247-
return true
248-
}
249-
if err.cause == nil {
250-
return false
251-
}
252-
err = err.cause.(*structured)
253-
return true
254-
}
255-
if stackPosition < len(err.callStack) {
256-
buf.WriteString("at ")
230+
for {
231+
for stackPosition := 0; stackPosition < len(err.callStack); stackPosition++ {
257232
call := err.callStack[stackPosition]
258-
fmt.Fprintf(buf, "%+n (%s:%d)", call, call, call)
259-
stackPosition++
233+
fmt.Fprintf(w, "%s at %+n (%s:%d)\n", linePrefix, call, call, call)
260234
}
261-
if stackPosition >= len(err.callStack) {
262-
switch cause := err.cause.(type) {
263-
case *structured:
264-
err = cause
265-
indent = false
266-
stackPosition = 0
267-
switchedCause = true
268-
default:
269-
return false
270-
}
235+
cause, ok := err.cause.(*structured)
236+
if !ok || cause == nil {
237+
return
271238
}
272-
return err != nil
239+
err = cause
240+
fmt.Fprintf(w, "%sCaused by: %v\n", linePrefix, err)
273241
}
274242
}
275243

‎src/github.com/getlantern/errors/errors_test.go

+3-8
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,9 @@ func TestNewWithCause(t *testing.T) {
6262

6363
// Make sure that stacktrace prints out okay
6464
buf := &bytes.Buffer{}
65-
print := outer.MultiLinePrinter()
66-
for {
67-
more := print(buf)
68-
buf.WriteByte('\n')
69-
if !more {
70-
break
71-
}
72-
}
65+
buf.WriteString(outer.Error())
66+
buf.WriteByte('\n')
67+
outer.PrintStack(buf, "")
7368
expected := `Hello World
7469
at github.com/getlantern/errors.TestNewWithCause (errors_test.go:999)
7570
at testing.tRunner (testing.go:999)

‎src/github.com/getlantern/golog/golog.go

+15-71
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// debug messages to stdout. Trace logging is also supported.
33
// Trace logs go to stdout as well, but they are only written if the program
44
// is run with environment variable "TRACE=true".
5-
// A stack dump will be printed after the message if "PRINT_STACK=true".
65
package golog
76

87
import (
@@ -67,16 +66,6 @@ type outputs struct {
6766
DebugOut io.Writer
6867
}
6968

70-
// MultiLine is an interface for arguments that support multi-line output.
71-
type MultiLine interface {
72-
// MultiLinePrinter returns a function that can be used to print the
73-
// multi-line output. The returned function writes one line to the buffer and
74-
// returns true if there are more lines to write. This function does not need
75-
// to take care of trailing carriage returns, golog handles that
76-
// automatically.
77-
MultiLinePrinter() func(buf *bytes.Buffer) bool
78-
}
79-
8069
// ErrorReporter is a function to which the logger will report errors.
8170
// It the given error and corresponding message along with associated ops
8271
// context. This should return quickly as it executes on the critical code
@@ -145,20 +134,15 @@ func LoggerFor(prefix string) Logger {
145134
l.traceOut = ioutil.Discard
146135
}
147136

148-
printStack := os.Getenv("PRINT_STACK")
149-
l.printStack, _ = strconv.ParseBool(printStack)
150-
151137
return l
152138
}
153139

154140
type logger struct {
155-
prefix string
156-
traceOn bool
157-
traceOut io.Writer
158-
printStack bool
159-
outs atomic.Value
160-
pc []uintptr
161-
funcForPc *runtime.Func
141+
prefix string
142+
traceOn bool
143+
traceOut io.Writer
144+
outs atomic.Value
145+
pc []uintptr
162146
}
163147

164148
// attaches the file and line number corresponding to
@@ -175,44 +159,27 @@ func (l *logger) print(out io.Writer, skipFrames int, severity string, arg inter
175159
defer bufferPool.Put(buf)
176160

177161
linePrefix := l.linePrefix(skipFrames)
178-
writeHeader := func() {
179-
buf.WriteString(severity)
180-
buf.WriteString(" ")
181-
buf.WriteString(linePrefix)
182-
}
162+
sp := severity + " " + linePrefix
163+
buf.WriteString(sp)
183164
if arg != nil {
184-
ml, isMultiline := arg.(MultiLine)
185-
if !isMultiline {
186-
writeHeader()
187-
fmt.Fprintf(buf, "%v", arg)
165+
if err, isError := arg.(errors.Error); isError && err != nil {
166+
buf.WriteString(err.Error())
188167
printContext(buf, arg)
189168
buf.WriteByte('\n')
190-
} else {
191-
mlp := ml.MultiLinePrinter()
192-
first := true
193-
for {
194-
writeHeader()
195-
more := mlp(buf)
196-
if first {
197-
printContext(buf, arg)
198-
first = false
199-
}
200-
buf.WriteByte('\n')
201-
if !more {
202-
break
203-
}
169+
if severity == "FATAL" || severity == "ERROR" {
170+
err.PrintStack(buf, sp)
204171
}
172+
} else {
173+
fmt.Fprintf(buf, "%v", arg)
174+
printContext(buf, arg)
175+
buf.WriteByte('\n')
205176
}
206177
}
207178
b := []byte(hidden.Clean(buf.String()))
208179
_, err := out.Write(b)
209180
if err != nil {
210181
errorOnLogging(err)
211182
}
212-
if l.printStack {
213-
l.doPrintStack()
214-
}
215-
216183
return linePrefix
217184
}
218185

@@ -232,9 +199,6 @@ func (l *logger) printf(out io.Writer, skipFrames int, severity string, err erro
232199
if err2 != nil {
233200
errorOnLogging(err)
234201
}
235-
if l.printStack {
236-
l.doPrintStack()
237-
}
238202
return linePrefix
239203
}
240204

@@ -349,26 +313,6 @@ func (l *logger) AsStdLogger() *log.Logger {
349313
return log.New(&errorWriter{l}, "", 0)
350314
}
351315

352-
func (l *logger) doPrintStack() {
353-
var b []byte
354-
buf := bytes.NewBuffer(b)
355-
for _, pc := range l.pc {
356-
funcForPc := runtime.FuncForPC(pc)
357-
if funcForPc == nil {
358-
break
359-
}
360-
name := funcForPc.Name()
361-
if strings.HasPrefix(name, "runtime.") {
362-
break
363-
}
364-
file, line := funcForPc.FileLine(pc)
365-
fmt.Fprintf(buf, "\t%s\t%s: %d\n", name, file, line)
366-
}
367-
if _, err := buf.WriteTo(os.Stderr); err != nil {
368-
errorOnLogging(err)
369-
}
370-
}
371-
372316
func errorOnLogging(err error) {
373317
fmt.Fprintf(os.Stderr, "Unable to log: %v\n", err)
374318
}

0 commit comments

Comments
 (0)
Please sign in to comment.