Files
golib/errors/errors.go
nabbar e047c986a6 Package Errors:
- Add interface Errors to expose func for collection of errors

Package Server:
- Add runner packages for start/stop & ticker process launch in goroutines
- Runner Start/Stop : register a start and a stop function called into a managment instance of goroutines, expose package Server interface
- Runner Ticker : register a func periodycly called into a managment instance of goroutine with a time ticker, expose package server interface
- Add tools function to run x times a function or periodicly with a check function

Package HttpServer:
- Remove old run managment instance and use new Start&Stop Runner instead self runner
- Replace the poller in server start / stop with package server tools function
- Adjust code following this change
- Add in healthcheck a test of dialing to server binding network to perform the healthcheck
- Remove WaitNotify funct (cannot having multiple of waitnotify in same app) : keep waitnotify function in package config

Package Monitor:
- Remove old running system to use package server/runner/ticker
- Adjust code following

Package Cobra :
- Fix minor bug with writing configure
- Optimize code

Bump dependencies
2023-04-06 13:17:38 +02:00

604 lines
14 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 FuncMap func(e Error) bool
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
//GetParent return a slice of Error interface for each parent error with or without the first error.
GetParent(withMainError bool) []Error
//Map run a function on each func and parent. If the function return false, the loop stop.
Map(fct FuncMap) 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)
}
type Errors interface {
// ErrorsLast return the last registered error
ErrorsLast() error
// ErrorsList return a slice of all registered errors
ErrorsList() []error
}
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) GetParent(withMainError bool) []Error {
var res = make([]Error, 0)
if withMainError {
res = append(res, &errors{
c: e.c,
e: e.e,
p: nil,
t: e.t,
})
}
if len(e.p) > 0 {
for _, er := range e.p {
res = append(res, er.GetParent(true)...)
}
}
return res
}
func (e *errors) SetParent(parent ...error) {
e.p = make([]Error, 0)
e.AddParent(parent...)
}
func (e *errors) Map(fct FuncMap) bool {
if !fct(e) {
return false
} else if len(e.p) > 0 {
for _, er := range e.p {
if !er.Map(fct) {
return false
}
}
}
return true
}
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 {
for _, s := range v.GetErrorSlice() {
r = append(r, s)
}
}
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)
}
}