-
Notifications
You must be signed in to change notification settings - Fork 0
/
errors.go
185 lines (164 loc) · 5.01 KB
/
errors.go
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package errors
import (
"errors"
"fmt"
"github.com/GabrielHCataldo/go-helper/helper"
"github.com/GabrielHCataldo/go-logger/logger"
"regexp"
"runtime/debug"
"strings"
)
const regexErrorDetail = `\[CAUSE]: \(([^:]+):(\d+)\) ([^:]+): (.+?) \[STACK]:\s*([\s\S]+)`
type ErrorDetail struct {
file string
line string
funcName string
message string
debugStack string
}
// New error with space separated message values, if the message parameter is empty we return a
// nil value, otherwise returns normal value
func New(message ...any) error {
msg := printMessage(message...)
if helper.IsEmpty(msg) {
return nil
}
file, line, funcName := helper.GetCallerInfo(2)
debugStack := debug.Stack()
return &ErrorDetail{
file: file,
line: line,
funcName: funcName,
message: msg,
debugStack: string(debugStack),
}
}
// NewSkipCaller error with message values separate per space and skipCaller, if the message parameter is empty we return a
// nil value, otherwise returns normal value
func NewSkipCaller(skipCaller int, message ...any) error {
msg := printMessage(message...)
if helper.IsEmpty(msg) {
return nil
}
file, line, funcName := helper.GetCallerInfo(skipCaller + 1)
debugStack := debug.Stack()
return &ErrorDetail{
file: file,
line: line,
funcName: funcName,
message: msg,
debugStack: string(debugStack),
}
}
// Is validate equal errors
func Is(err, target error) bool {
if IsErrorDetail(err) {
errDetails := Details(err)
err = errors.New(errDetails.GetMessage())
}
if IsErrorDetail(target) {
errDetails := Details(target)
target = errors.New(errDetails.GetMessage())
}
return helper.IsNotNil(err) && helper.Equals(err, target)
}
// IsNot validate not equal errors
func IsNot(err, target error) bool {
return !Is(err, target)
}
// Contains validate message target contains on message err
func Contains(err, target error) bool {
if IsErrorDetail(err) {
errDetails := Details(err)
err = errors.New(errDetails.GetMessage())
}
if IsErrorDetail(target) {
errDetails := Details(target)
target = errors.New(errDetails.GetMessage())
}
return helper.IsNotNil(err) && helper.IsNotNil(target) && strings.Contains(err.Error(), target.Error())
}
// NotContains validate message target not contains on message err
func NotContains(err, target error) bool {
return !Contains(err, target)
}
// Error print the error as a string, genetic implementation of error in go
func (e *ErrorDetail) Error() string {
return fmt.Sprint("[CAUSE]: ", e.GetCause(), " [STACK]: \n", e.debugStack)
}
// PrintStackTrace print red message with detail error and debug stack
func (e *ErrorDetail) PrintStackTrace() {
logger.ErrorSkipCaller(2, e.debugStack)
}
// PrintCause print red message with cause error
func (e *ErrorDetail) PrintCause() {
logger.ErrorSkipCaller(2, e.GetCause())
}
// GetCause returns formatted error cause
func (e *ErrorDetail) GetCause() string {
return fmt.Sprint("(", e.file, ":", e.line, ")", " ", e.funcName, ": ", e.message)
}
// GetMessage returns the value of the error message field
func (e *ErrorDetail) GetMessage() string {
return e.message
}
// GetFile returns the value of the error file field
func (e *ErrorDetail) GetFile() string {
return e.file
}
// GetLine returns the value of the error line field
func (e *ErrorDetail) GetLine() int {
return helper.SimpleConvertToInt(e.line)
}
// GetFuncName returns the value of the error funcName field
func (e *ErrorDetail) GetFuncName() string {
return e.funcName
}
// GetDebugStack returns the value of the error debugStack field
func (e *ErrorDetail) GetDebugStack() string {
return e.debugStack
}
// IsErrorDetail check if the error is an ErrorDetail containing the pattern with file name, line, function name,
// message and debugStack
func IsErrorDetail(err error) bool {
regex := regexp.MustCompile(regexErrorDetail)
return helper.IsNotNil(err) && regex.MatchString(err.Error())
}
// Details we obtain the values of an error passed in the parameter, and transform them into an ErrorDetail object, if
// the passed parameter is null, the return will also be null and if it is not in the desired errorDetail pattern, we
// return a new ErrDetail with the message being the err passed in the parameter.
func Details(err error) *ErrorDetail {
if helper.IsNil(err) {
return nil
}
var file string
var line string
var funcName string
var message string
var debugStack string
regex := regexp.MustCompile(regexErrorDetail)
matches := regex.FindStringSubmatch(err.Error())
if helper.IsNotEmpty(matches) {
file = matches[1]
line = matches[2]
funcName = matches[3]
message = matches[4]
debugStack = matches[5]
} else {
file, line, funcName = helper.GetCallerInfo(2)
debugStack = string(debug.Stack())
}
return &ErrorDetail{
file: file,
line: line,
funcName: funcName,
message: message,
debugStack: debugStack,
}
}
func printMessage(v ...any) string {
msg := helper.Sprintln(v...)
msg = strings.ReplaceAll(msg, "[STACK]", "")
msg = strings.ReplaceAll(msg, "[CAUSE]", "")
return msg
}