forked from rs/zerolog
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(rs#470) Localize github.com/pkg/errors
Signed-off-by: Bhargav Ravuri <vaguecoder0to.n@gmail.com>
- Loading branch information
1 parent
c2b9d0e
commit 9a7fb84
Showing
6 changed files
with
557 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package errors | ||
|
||
// New returns an error with the supplied message. | ||
// New also records the stack trace at the point it was called. | ||
func New(message string) error { | ||
return &fundamental{ | ||
msg: message, | ||
Stack: callers(), | ||
} | ||
} | ||
|
||
// Wrap returns an error annotating err with a stack trace | ||
// at the point Wrap is called, and the supplied message. | ||
// If err is nil, Wrap returns nil. | ||
func Wrap(err error, message string) error { | ||
if err == nil { | ||
return nil | ||
} | ||
err = &withMessage{ | ||
cause: err, | ||
msg: message, | ||
} | ||
return &withStack{ | ||
err, | ||
callers(), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package errors_test | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"io" | ||
"testing" | ||
|
||
internalErrors "github.com/rs/zerolog/internal/errors" | ||
) | ||
|
||
func TestNew(t *testing.T) { | ||
tests := []struct { | ||
err string | ||
want error | ||
}{ | ||
{"", fmt.Errorf("")}, | ||
{"foo", fmt.Errorf("foo")}, | ||
{"foo", internalErrors.New("foo")}, | ||
{"string with format specifiers: %v", errors.New("string with format specifiers: %v")}, | ||
} | ||
|
||
for _, tt := range tests { | ||
got := internalErrors.New(tt.err) | ||
if got.Error() != tt.want.Error() { | ||
t.Errorf("New.Error(): got: %q, want %q", got, tt.want) | ||
} | ||
} | ||
} | ||
|
||
func TestWrapNil(t *testing.T) { | ||
got := internalErrors.Wrap(nil, "no error") | ||
if got != nil { | ||
t.Errorf("Wrap(nil, \"no error\"): got %#v, expected nil", got) | ||
} | ||
} | ||
|
||
func TestWrap(t *testing.T) { | ||
tests := []struct { | ||
err error | ||
message string | ||
want string | ||
}{ | ||
{io.EOF, "read error", "read error: EOF"}, | ||
{internalErrors.Wrap(io.EOF, "read error"), "client error", "client error: read error: EOF"}, | ||
} | ||
|
||
for _, tt := range tests { | ||
var got string | ||
if tt.err != nil { | ||
got = internalErrors.Wrap(tt.err, tt.message).Error() | ||
} | ||
if got != tt.want { | ||
t.Errorf("Wrap(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package errors | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"path" | ||
"runtime" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// Stack represents a stack of program counters. | ||
type Stack []uintptr | ||
|
||
// StackTrace prints the stack trace of program. | ||
func (s *Stack) StackTrace() StackTrace { | ||
f := make([]Frame, len(*s)) | ||
for i := 0; i < len(f); i++ { | ||
f[i] = Frame((*s)[i]) | ||
} | ||
return f | ||
} | ||
|
||
// fundamental is an error that has a message and a stack, but no caller. | ||
type fundamental struct { | ||
msg string | ||
*Stack | ||
} | ||
|
||
// Error prints the error message string | ||
func (f *fundamental) Error() string { | ||
return f.msg | ||
} | ||
|
||
// withStack is error with caller stack | ||
type withStack struct { | ||
error | ||
*Stack | ||
} | ||
|
||
// withMessage is error with added message | ||
type withMessage struct { | ||
cause error | ||
msg string | ||
} | ||
|
||
// Error prints the error message string with cause | ||
func (w *withMessage) Error() string { | ||
return w.msg + ": " + w.cause.Error() | ||
} | ||
|
||
// Frame represents a program counter inside a stack frame. | ||
// For historical reasons if Frame is interpreted as a uintptr | ||
// its value represents the program counter + 1. | ||
type Frame uintptr | ||
|
||
// pc returns the program counter for this frame; | ||
// multiple frames may have the same PC value. | ||
func (f Frame) pc() uintptr { | ||
return uintptr(f) - 1 | ||
} | ||
|
||
// file returns the full path to the file that contains the | ||
// function for this Frame's pc. | ||
func (f Frame) file() string { | ||
fn := runtime.FuncForPC(f.pc()) | ||
if fn == nil { | ||
return "unknown" | ||
} | ||
file, _ := fn.FileLine(f.pc()) | ||
return file | ||
} | ||
|
||
// line returns the line number of source code of the | ||
// function for this Frame's pc. | ||
func (f Frame) line() int { | ||
fn := runtime.FuncForPC(f.pc()) | ||
if fn == nil { | ||
return 0 | ||
} | ||
_, line := fn.FileLine(f.pc()) | ||
return line | ||
} | ||
|
||
// name returns the name of this function, if known. | ||
func (f Frame) name() string { | ||
fn := runtime.FuncForPC(f.pc()) | ||
if fn == nil { | ||
return "unknown" | ||
} | ||
return fn.Name() | ||
} | ||
|
||
// Format formats the frame according to the fmt.Formatter interface. | ||
// | ||
// %s source file | ||
// %d source line | ||
// %n function name | ||
// %v equivalent to %s:%d | ||
// | ||
// Format accepts flags that alter the printing of some verbs, as follows: | ||
// | ||
// %+s function name and path of source file relative to the compile time | ||
// GOPATH separated by \n\t (<funcname>\n\t<path>) | ||
// %+v equivalent to %+s:%d | ||
func (f Frame) Format(s fmt.State, verb rune) { | ||
switch verb { | ||
case 's': | ||
switch { | ||
case s.Flag('+'): | ||
_, _ = io.WriteString(s, f.name()) | ||
_, _ = io.WriteString(s, "\n\t") | ||
_, _ = io.WriteString(s, f.file()) | ||
default: | ||
_, _ = io.WriteString(s, path.Base(f.file())) | ||
} | ||
case 'd': | ||
_, _ = io.WriteString(s, strconv.Itoa(f.line())) | ||
case 'n': | ||
_, _ = io.WriteString(s, funcName(f.name())) | ||
case 'v': | ||
f.Format(s, 's') | ||
_, _ = io.WriteString(s, ":") | ||
f.Format(s, 'd') | ||
} | ||
} | ||
|
||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest). | ||
type StackTrace []Frame | ||
|
||
// callers gives caller function's stack | ||
func callers() *Stack { | ||
const depth = 32 | ||
var pcs [depth]uintptr | ||
n := runtime.Callers(3, pcs[:]) | ||
var st Stack = pcs[0:n] | ||
return &st | ||
} | ||
|
||
// funcName removes the path prefix component of a function's name reported by func.Name(). | ||
func funcName(name string) string { | ||
i := strings.LastIndex(name, "/") | ||
name = name[i+1:] | ||
i = strings.Index(name, ".") | ||
return name[i+1:] | ||
} |
Oops, something went wrong.