mirror of
https://github.com/nabbar/golib.git
synced 2025-10-06 00:06:50 +08:00

- Fix bug : apply file permission on directory Package errors : - Add function dedicated to recorved : add at least 5 frame trace into message - Add function to retrieve at least 5 frame not in golib, vendor and runtime root package - Fix error in frame extraction Package Logger : - Add mutex to fix race error - Fix missing origin error while return error for open/create file - Clean useless commented code Package Router : - Skip gin context abort if context still aborted - refactory recovery error to liberr.NewErrorRecovered to include enought trace
553 lines
13 KiB
Go
553 lines
13 KiB
Go
/*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2020 Nicolas JUHEL
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*
|
|
*/
|
|
|
|
package errors
|
|
|
|
import (
|
|
errs "errors"
|
|
"fmt"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
defaultGlue = ", "
|
|
defaultPattern = "[Error #%s] %s"
|
|
defaultPatternTrace = "[Error #%s] %s (%s)"
|
|
)
|
|
|
|
// SetTracePathFilter define the glue string to be used to join main error with parents'errors.
|
|
func SetDefaultGlue(glue string) {
|
|
defaultGlue = glue
|
|
}
|
|
|
|
// GetDefaultGlue return the current glue used to joins errors with parents.
|
|
func GetDefaultGlue() string {
|
|
return defaultGlue
|
|
}
|
|
|
|
// GetDefaultPatternTrace define the pattern to be used for string of error with code.
|
|
// The pattern is fmt pattern with 2 inputs in order : code, message.
|
|
func SetDefaultPattern(pattern string) {
|
|
defaultPattern = pattern
|
|
}
|
|
|
|
// GetDefaultPattern return the current pattern used for string of error with code.
|
|
// The pattern is fmt pattern with 2 inputs in order : code, message.
|
|
func GetDefaultPattern() string {
|
|
return defaultPattern
|
|
}
|
|
|
|
// SetDefaultPatternTrace define the pattern to be used for string of error with code and trace.
|
|
// The pattern is fmt pattern with 3 inputs in order : code, message, trace.
|
|
func SetDefaultPatternTrace(patternTrace string) {
|
|
defaultPatternTrace = patternTrace
|
|
}
|
|
|
|
// GetDefaultPatternTrace return the current pattern used for string of error with code and trace.
|
|
// The pattern is fmt pattern with 3 inputs in order : code, message, trace.
|
|
func GetDefaultPatternTrace() string {
|
|
return defaultPatternTrace
|
|
}
|
|
|
|
// SetTracePathFilter customize the filter apply to filepath on trace.
|
|
func SetTracePathFilter(path string) {
|
|
filterPkg = path
|
|
}
|
|
|
|
type errors struct {
|
|
c uint16
|
|
e string
|
|
p []Error
|
|
t runtime.Frame
|
|
}
|
|
|
|
type Error interface {
|
|
//IsCodeError check if the given error code is matching with the current Error
|
|
IsCodeError(code CodeError) bool
|
|
//HasCodeError check if current error or parent has the given error code
|
|
HasCodeError(code CodeError) bool
|
|
//GetCodeError return the CodeError value of the current error
|
|
GetCodeError() CodeError
|
|
//GetCodeErrorParent return a slice of CodeError value of all parent Error and the code of the current Error
|
|
GetCodeErrorParent() []CodeError
|
|
|
|
//IsError check if the given error params is a valid error and not a nil pointer
|
|
IsError(e error) bool
|
|
//HasError check if the given error in params is still in parent error
|
|
HasError(err error) bool
|
|
//HasParent check if the current Error has any valid parent
|
|
HasParent() bool
|
|
|
|
//AddParent will add all no empty given error into parent of the current Error pointer
|
|
AddParent(parent ...error)
|
|
//SetParent will replace all parent with the given error list
|
|
SetParent(parent ...error)
|
|
//AddParentError will add all no empty given Error into parent of the current Error pointer
|
|
AddParentError(parent ...Error)
|
|
//SetParentError will replace all parent with the given Error list
|
|
SetParentError(parent ...Error)
|
|
|
|
//Code is used to return the code of current Error, as string
|
|
Code() string
|
|
//CodeFull is used to return a joint string of code of current Error and code of all parent Error
|
|
CodeFull(glue string) string
|
|
//CodeSlice is used to return a slice string of all code of current Error (main and parent)
|
|
CodeSlice() []string
|
|
|
|
//CodeError is used to return a composed string of current Error code with message, for current Error and no parent
|
|
CodeError(pattern string) string
|
|
//CodeErrorFull is used to return a composed string of couple error code with message, for current Error and all parent
|
|
CodeErrorFull(pattern, glue string) string
|
|
//CodeErrorSlice is used to return a composed string slice of couple error code with message, for current Error and all parent
|
|
CodeErrorSlice(pattern string) []string
|
|
|
|
//CodeErrorTrace is used to return a composed string of current Error code with message and trace information, for current Error and no parent
|
|
CodeErrorTrace(pattern string) string
|
|
//CodeErrorTraceFull is used to return a composed string of couple error code with message and trace information, for current Error and all parent
|
|
CodeErrorTraceFull(pattern, glue string) string
|
|
//CodeErrorTraceSlice is used to return a composed string slice of couple error code with message and trace information, for current Error and all parent
|
|
CodeErrorTraceSlice(pattern string) []string
|
|
|
|
//Error is used to match with error interface
|
|
//this function will return a mixed result depends of the configuration defined by calling SetModeReturnError
|
|
Error() string
|
|
|
|
//StringError is used to return the error message, for current Error and no parent
|
|
StringError() string
|
|
//StringErrorFull is used to return the error message, for current Error and all parent
|
|
StringErrorFull(glue string) string
|
|
//StringErrorSlice is used to return the error message, for current Error and all parent, as a slice of string
|
|
StringErrorSlice() []string
|
|
|
|
//GetError is used to return a new error interface based of the current error (and no parent)
|
|
GetError() error
|
|
//GetErrorFull is used to return a new error interface based of the current error with all parent
|
|
GetErrorFull(glue string) error
|
|
//GetErrorSlice is used to return a slice of new error interface, based of the current error and all parent
|
|
GetErrorSlice() []error
|
|
|
|
//GetIError is used to return a Error interface pointer based of current Error
|
|
GetIError() Error
|
|
//GetIErrorSlice is used to return a slice of Error interface pointer, based of current Error and all parents
|
|
GetIErrorSlice() []Error
|
|
|
|
//GetTrace will return a comped string for the trace of the current Error
|
|
GetTrace() string
|
|
//GetTrace will return a slice of comped string fpr the trace of the current Error and all parent
|
|
GetTraceSlice() []string
|
|
|
|
//Return will transform the current Error into a given pointer that implement the Return interface
|
|
Return(r Return)
|
|
//ReturnError will send the current Error value to the given function ReturnError
|
|
ReturnError(f ReturnError)
|
|
//ReturnParent will send all parent information of the current Error value to the given function ReturnError
|
|
ReturnParent(f ReturnError)
|
|
}
|
|
|
|
func MakeErrorIfError(err ...Error) Error {
|
|
var e Error = nil
|
|
|
|
for _, p := range err {
|
|
if p == nil {
|
|
continue
|
|
}
|
|
if e == nil {
|
|
e = p
|
|
} else {
|
|
e.AddParentError(p)
|
|
}
|
|
}
|
|
|
|
return e
|
|
}
|
|
|
|
func NewError(code uint16, message string, parent Error) Error {
|
|
var p = make([]Error, 0)
|
|
|
|
if parent != nil {
|
|
p = parent.GetIErrorSlice()
|
|
}
|
|
|
|
return &errors{
|
|
c: code,
|
|
e: message,
|
|
p: p,
|
|
t: getFrame(),
|
|
}
|
|
}
|
|
|
|
func NewErrorTrace(code int, msg string, file string, line int, parent Error) Error {
|
|
var p = make([]Error, 0)
|
|
|
|
if parent != nil {
|
|
p = parent.GetIErrorSlice()
|
|
}
|
|
|
|
return &errors{
|
|
c: uint16(code),
|
|
e: msg,
|
|
p: p,
|
|
t: runtime.Frame{
|
|
File: file,
|
|
Line: line,
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewErrorRecovered(msg string, recovered string, parent ...error) Error {
|
|
var p = make([]Error, 0)
|
|
|
|
if recovered != "" {
|
|
p = append(p, &errors{
|
|
c: 0,
|
|
e: recovered,
|
|
p: nil,
|
|
})
|
|
}
|
|
|
|
if len(parent) > 0 {
|
|
for _, err := range parent {
|
|
if err == nil {
|
|
continue
|
|
}
|
|
|
|
p = append(p, &errors{
|
|
c: 0,
|
|
e: err.Error(),
|
|
p: nil,
|
|
})
|
|
}
|
|
}
|
|
|
|
for _, t := range getFrameVendor() {
|
|
if t == getNilFrame() {
|
|
continue
|
|
}
|
|
msg += "\n " + fmt.Sprintf("Fct: %s - File: %s - Line: %d", t.Function, t.File, t.Line)
|
|
}
|
|
|
|
return &errors{
|
|
c: 0,
|
|
e: msg,
|
|
p: p,
|
|
t: getFrame(),
|
|
}
|
|
}
|
|
|
|
func NewErrorIferror(code uint16, message string, parent error) Error {
|
|
if parent == nil {
|
|
return nil
|
|
}
|
|
|
|
p := make([]Error, 0)
|
|
p = append(p, &errors{
|
|
c: 0,
|
|
e: parent.Error(),
|
|
p: nil,
|
|
})
|
|
|
|
return &errors{
|
|
c: code,
|
|
e: message,
|
|
p: p,
|
|
t: getFrame(),
|
|
}
|
|
}
|
|
|
|
func NewErrorIfError(code uint16, message string, parent Error) Error {
|
|
if parent == nil {
|
|
return nil
|
|
}
|
|
|
|
return &errors{
|
|
c: code,
|
|
e: message,
|
|
p: parent.GetIErrorSlice(),
|
|
t: getFrame(),
|
|
}
|
|
}
|
|
|
|
func (e *errors) AddParent(parent ...error) {
|
|
for _, v := range parent {
|
|
if v != nil {
|
|
e.p = append(e.p, &errors{
|
|
c: 0,
|
|
e: v.Error(),
|
|
p: nil,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func (e *errors) IsCodeError(code CodeError) bool {
|
|
return e.c == code.GetUint16()
|
|
}
|
|
|
|
func (e *errors) IsError(err error) bool {
|
|
return e.e == err.Error()
|
|
}
|
|
|
|
func (e *errors) HasCodeError(code CodeError) bool {
|
|
if e.IsCodeError(code) {
|
|
return true
|
|
}
|
|
|
|
for _, p := range e.p {
|
|
if p.IsCodeError(code) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (e *errors) GetCodeError() CodeError {
|
|
return CodeError(e.c)
|
|
}
|
|
|
|
func (e *errors) GetCodeErrorParent() []CodeError {
|
|
var res = make([]CodeError, 0)
|
|
|
|
res = append(res, e.GetCodeError())
|
|
for _, p := range e.p {
|
|
res = append(res, p.GetCodeErrorParent()...)
|
|
}
|
|
|
|
return unicCodeSlice(res)
|
|
}
|
|
|
|
func (e *errors) HasError(err error) bool {
|
|
if e.IsError(err) {
|
|
return true
|
|
}
|
|
|
|
for _, p := range e.p {
|
|
if p.IsError(err) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (e *errors) HasParent() bool {
|
|
return len(e.p) > 0
|
|
}
|
|
|
|
func (e *errors) SetParent(parent ...error) {
|
|
e.p = make([]Error, 0)
|
|
e.AddParent(parent...)
|
|
}
|
|
|
|
func (e *errors) AddParentError(parent ...Error) {
|
|
for _, p := range parent {
|
|
if p != nil {
|
|
e.p = append(e.p, p)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (e *errors) SetParentError(parent ...Error) {
|
|
e.p = parent
|
|
}
|
|
|
|
func (e *errors) Code() string {
|
|
return strconv.Itoa(int(e.c))
|
|
}
|
|
|
|
func (e *errors) CodeFull(glue string) string {
|
|
if glue == "" {
|
|
glue = defaultGlue
|
|
}
|
|
|
|
return strings.Join(e.CodeSlice(), glue)
|
|
}
|
|
|
|
func (e *errors) CodeSlice() []string {
|
|
var r = []string{e.Code()}
|
|
|
|
for _, v := range e.p {
|
|
r = append(r, v.Code())
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func (e *errors) Error() string {
|
|
return modeError.error(e)
|
|
}
|
|
|
|
func (e *errors) StringError() string {
|
|
return e.e
|
|
}
|
|
|
|
func (e *errors) StringErrorFull(glue string) string {
|
|
if glue == "" {
|
|
glue = defaultGlue
|
|
}
|
|
|
|
return strings.Join(e.StringErrorSlice(), glue)
|
|
}
|
|
|
|
func (e *errors) StringErrorSlice() []string {
|
|
var r = []string{e.StringError()}
|
|
|
|
for _, v := range e.p {
|
|
r = append(r, v.Error())
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func (e *errors) GetError() error {
|
|
//nolint goerr113
|
|
return errs.New(e.e)
|
|
}
|
|
|
|
func (e *errors) GetErrorFull(glue string) error {
|
|
//nolint goerr113
|
|
return errs.New(e.StringErrorFull(glue))
|
|
}
|
|
|
|
func (e *errors) GetErrorSlice() []error {
|
|
var r = []error{e.GetError()}
|
|
|
|
for _, v := range e.p {
|
|
r = append(r, v.GetError())
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func (e *errors) GetIError() Error {
|
|
return e
|
|
}
|
|
|
|
func (e *errors) GetIErrorSlice() []Error {
|
|
var r = []Error{e}
|
|
|
|
for _, v := range e.p {
|
|
r = append(r, v.GetIError())
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func (e *errors) GetTrace() string {
|
|
if e.t.File != "" {
|
|
return fmt.Sprintf("%s#%d", filterPath(e.t.File), e.t.Line)
|
|
} else if e.t.Function != "" {
|
|
return fmt.Sprintf("%s#%d", e.t.Function, e.t.Line)
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func (e *errors) GetTraceSlice() []string {
|
|
var r = []string{e.GetTrace()}
|
|
|
|
for _, v := range e.p {
|
|
if t := v.GetTrace(); t != "" {
|
|
r = append(r, v.GetTrace())
|
|
}
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func (e *errors) CodeError(pattern string) string {
|
|
if pattern == "" {
|
|
pattern = defaultPattern
|
|
}
|
|
return fmt.Sprintf(pattern, e.Code(), e.StringError())
|
|
}
|
|
|
|
func (e *errors) CodeErrorFull(pattern, glue string) string {
|
|
if glue == "" {
|
|
glue = defaultGlue
|
|
}
|
|
|
|
return strings.Join(e.CodeErrorSlice(pattern), glue)
|
|
}
|
|
|
|
func (e *errors) CodeErrorSlice(pattern string) []string {
|
|
var r = []string{e.CodeError(pattern)}
|
|
|
|
for _, v := range e.p {
|
|
r = append(r, v.CodeError(pattern))
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func (e *errors) CodeErrorTrace(pattern string) string {
|
|
if pattern == "" {
|
|
pattern = defaultPatternTrace
|
|
}
|
|
|
|
return fmt.Sprintf(pattern, e.Code(), e.StringError(), e.GetTrace())
|
|
}
|
|
|
|
func (e *errors) CodeErrorTraceFull(pattern, glue string) string {
|
|
if glue == "" {
|
|
glue = defaultGlue
|
|
}
|
|
|
|
return strings.Join(e.CodeErrorTraceSlice(pattern), glue)
|
|
}
|
|
|
|
func (e *errors) CodeErrorTraceSlice(pattern string) []string {
|
|
var r = []string{e.CodeErrorTrace(pattern)}
|
|
|
|
for _, v := range e.p {
|
|
r = append(r, v.CodeErrorTrace(pattern))
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func (e *errors) Return(r Return) {
|
|
e.ReturnError(r.SetError)
|
|
e.ReturnParent(r.AddParent)
|
|
}
|
|
|
|
func (e errors) ReturnError(f ReturnError) {
|
|
if e.t.File != "" {
|
|
f(int(e.c), e.e, e.t.File, e.t.Line)
|
|
} else {
|
|
f(int(e.c), e.e, e.t.Function, e.t.Line)
|
|
}
|
|
}
|
|
|
|
func (e errors) ReturnParent(f ReturnError) {
|
|
for _, p := range e.p {
|
|
p.ReturnError(f)
|
|
p.ReturnParent(f)
|
|
}
|
|
}
|