-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrors.go
More file actions
129 lines (112 loc) · 2.93 KB
/
errors.go
File metadata and controls
129 lines (112 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package errors
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"runtime"
"strconv"
"strings"
"time"
)
//errorWriter is a writer of the errors produced by this
//package. By default errors are discarted
var errorWriter = ioutil.Discard
//SetLogger sets the default output for error logging.
//If this function is not called, errors are discarted
func SetLogger(w io.Writer) {
errorWriter = w
}
func logError(e *Error) {
_, file, line, ok := runtime.Caller(2) // logger + public function.
if ok {
// Truncate file name at last file name separator.
if index := strings.LastIndex(file, "/"); index >= 0 {
file = file[index+1:]
} else if index = strings.LastIndex(file, "\\"); index >= 0 {
file = file[index+1:]
}
} else {
file = "???"
line = 1
}
fmt.Fprintln(errorWriter, file, line, e.Error(), time.Now().Local())
}
//Error describes a failed action with an status code
type Error struct {
code int
message string
}
//Error returns the message of the error plus
//its status code
func (e *Error) Error() string {
return fmt.Sprintf("Status %d : %s", e.code, e.message)
}
//Code returns the status code of the error
func (e *Error) Code() int {
return e.code
}
//WithStatus sets the given status code of this error
func (e *Error) WithStatus(status int) *Error {
e.code = status
return e
}
//New returns an error with the given message, and a zero status code
func New(message string) *Error {
e := &Error{message: message}
logError(e)
return e
}
//WithStatus annotates a new error with an status code
func WithStatus(code int, err error) *Error {
if err == nil {
return nil
}
e := &Error{code: code, message: err.Error()}
logError(e)
return e
}
//WithMessage anotates the error with an optional
func WithMessage(message string, code int, err error) *Error {
if err == nil {
return nil
}
msg := fmt.Sprintf("%s: %s", message, err.Error())
e := &Error{code: code, message: msg}
logError(e)
return e
}
//MarshalJSON satisfies the json.Marshaler interface
func (e *Error) MarshalJSON() ([]byte, error) {
errMap := map[string]string{
"error": e.message,
"code": strconv.Itoa(e.code),
}
return json.Marshal(errMap)
}
//StackError contains an error message with an status and the callees stack
type StackError struct {
err Error
*stack
}
//WithStack returns an error annotated with the stacktrace
func WithStack(message string, status int, err error) *StackError {
if err == nil {
return nil
}
msg := fmt.Sprintf("%s: %s", message, err.Error())
ex := Error{code: status, message: msg}
return &StackError{err: ex, stack: callers()}
}
//Error returns the annotated error with its status code and the stacktrace.
func (s *StackError) Error() string {
return fmt.Sprintf("%v%+v", s.err.Error(), s.stack)
}
//Code returns the status code of the error
func (s *StackError) Code() int {
return s.err.Code()
}
//WithStatus sets the given status to this error
func (s *StackError) WithStatus(status int) {
s.err.code = status
}