diff --git a/errors/errors.go b/errors/errors.go index 4e718bf5..0d03e477 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -219,6 +219,46 @@ func NewErrorTrace(code int, msg string, file string, line int, parent Error) Er } } +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 diff --git a/errors/trace.go b/errors/trace.go index 77f92392..a6b2aebb 100644 --- a/errors/trace.go +++ b/errors/trace.go @@ -45,9 +45,9 @@ func init() { } func getFrame() runtime.Frame { - // Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need - programCounters := make([]uintptr, 10, 255) - n := runtime.Callers(1, programCounters) + // Set size to targetFrameIndex+20 to ensure we have room for one more caller than we need + programCounters := make([]uintptr, 20, 255) + n := runtime.Callers(2, programCounters) if n > 0 { frames := runtime.CallersFrames(programCounters[:n]) @@ -62,9 +62,6 @@ func getFrame() runtime.Frame { if strings.Contains(frame.Function, currPkgs) { continue - } else { - // next frame to escape files errors - frame, _ = frames.Next() } return runtime.Frame{ @@ -78,6 +75,75 @@ func getFrame() runtime.Frame { return getNilFrame() } +func getFrameVendor() []runtime.Frame { + // Set size to targetFrameIndex+20 to ensure we have room for one more caller than we need + programCounters := make([]uintptr, 20, 255) + n := runtime.Callers(2, programCounters) + + res := make([]runtime.Frame, 0) + + if n > 0 { + frames := runtime.CallersFrames(programCounters[:n]) + more := true + + for more { + var ( + frame runtime.Frame + ) + + frame, more = frames.Next() + + item := runtime.Frame{ + Function: frame.Function, + File: frame.File, + Line: frame.Line, + } + + if strings.Contains(item.Function, currPkgs) { + continue + } else if strings.Contains(frame.File, "/vendor/") { + continue + } else if strings.HasPrefix(frame.Function, "runtime") { + continue + } else if frameInSlice(res, item) { + continue + } + + res = append(res, item) + + if len(res) > 4 { + return res + } + } + } + + return res +} + +func frameInSlice(s []runtime.Frame, f runtime.Frame) bool { + if len(s) < 1 { + return false + } + + for _, i := range s { + if i.Function != f.Function { + continue + } + + if i.File != f.File { + continue + } + + if i.Line != i.Line { + continue + } + + return true + } + + return false +} + func getNilFrame() runtime.Frame { return runtime.Frame{Function: "", File: "", Line: 0} } diff --git a/ioutils/tools.go b/ioutils/tools.go index b0ee389c..6bac146e 100644 --- a/ioutils/tools.go +++ b/ioutils/tools.go @@ -34,10 +34,14 @@ import ( ) func PathCheckCreate(isFile bool, path string, permFile os.FileMode, permDir os.FileMode) error { - if _, err := os.Stat(path); err != nil && !errors.Is(err, os.ErrNotExist) { + if inf, err := os.Stat(path); err != nil && !errors.Is(err, os.ErrNotExist) { return err } else if err == nil { - _ = os.Chmod(path, permFile) + if inf.IsDir() { + _ = os.Chmod(path, permDir) + } else { + _ = os.Chmod(path, permFile) + } return nil } @@ -52,5 +56,6 @@ func PathCheckCreate(isFile bool, path string, permFile os.FileMode, permDir os. } _ = os.Chmod(path, permFile) + return nil } diff --git a/logger/hookfile.go b/logger/hookfile.go index 25287a58..deb6c477 100644 --- a/logger/hookfile.go +++ b/logger/hookfile.go @@ -32,6 +32,7 @@ import ( "io" "os" "strings" + "sync" "github.com/nabbar/golib/ioutils" "github.com/sirupsen/logrus" @@ -44,6 +45,7 @@ type HookFile interface { } type _HookFile struct { + m sync.Mutex r logrus.Formatter l []logrus.Level s bool @@ -92,6 +94,7 @@ func NewHookFile(opt OptionsFile, format logrus.Formatter) (HookFile, error) { } obj := &_HookFile{ + m: sync.Mutex{}, r: format, l: LVLs, s: opt.DisableStack, @@ -143,6 +146,9 @@ func (o *_HookFile) Levels() []logrus.Level { } func (o *_HookFile) Fire(entry *logrus.Entry) error { + o.m.Lock() + defer o.m.Unlock() + ent := entry.Dup() ent.Level = entry.Level @@ -191,7 +197,6 @@ func (o *_HookFile) Fire(entry *logrus.Entry) error { func (o *_HookFile) Write(p []byte) (n int, err error) { h, e := o.openCreate() - defer func() { if h != nil { _ = h.Close() @@ -199,7 +204,7 @@ func (o *_HookFile) Write(p []byte) (n int, err error) { }() if e != nil { - return 0, fmt.Errorf("logrus.hookfile: cannot open '%s'", o.o.FilePath) + return 0, fmt.Errorf("logrus.hookfile: cannot open '%s': %v", o.o.FilePath, e) } else if n, e = h.Write(p); e != nil { return n, e } else { @@ -222,16 +227,4 @@ func (o *_HookFile) filterKey(f logrus.Fields, key string) logrus.Fields { delete(f, key) return f } - /* - var res = make(map[string]interface{}, 0) - - for k, v := range f { - if k == key { - continue - } - res[k] = v - } - - return res - */ } diff --git a/router/register.go b/router/register.go index ebcea4bf..b6d33d58 100644 --- a/router/register.go +++ b/router/register.go @@ -34,6 +34,8 @@ import ( "strings" "time" + liberr "github.com/nabbar/golib/errors" + "github.com/gin-gonic/gin" liblog "github.com/nabbar/golib/logger" ) @@ -122,7 +124,7 @@ func GinAccessLog(log liblog.FuncLog) gin.HandlerFunc { func GinErrorLog(log liblog.FuncLog) gin.HandlerFunc { return func(c *gin.Context) { defer func() { - var rec error + var rec liberr.Error if err := recover(); err != nil { // Check for a broken connection, as it is not really a @@ -138,16 +140,18 @@ func GinErrorLog(log liblog.FuncLog) gin.HandlerFunc { } if brokenPipe { - rec = fmt.Errorf("[Recovery] connection error: %s", err) + rec = liberr.NewErrorRecovered("[Recovery] connection error", fmt.Sprintf("%s", err)) } else { - rec = fmt.Errorf("[Recovery] panic recovered: %s", err) + rec = liberr.NewErrorRecovered("[Recovery] panic recovered", fmt.Sprintf("%s", err)) } - if brokenPipe { - // If the connection is dead, we can't write a status to it. - c.Abort() - } else { - c.AbortWithStatus(http.StatusInternalServerError) + if !c.IsAborted() { + if brokenPipe { + // If the connection is dead, we can't write a status to it. + c.Abort() + } else { + c.AbortWithStatus(http.StatusInternalServerError) + } } }