commons/pkg/stacktrace/main.go

86 lines
1.8 KiB
Go

package stacktrace
import (
"fmt"
"git.codebau.dev/goblins/commons/pkg/osdep"
"math"
"runtime"
)
const NoStatusCode = math.MinInt
type ErrorReporter struct {
EnableStacktraces bool
}
type StackElement struct {
File string
FunctionName string
Line int
}
type ErrorWithStacktrace struct {
error
ErrorCode int
Stack *[]*StackElement
}
func (s *ErrorWithStacktrace) build(enableStackTraces bool) {
if !enableStackTraces || s == nil || s.error == nil {
return
}
readingCallers := true
callerIncrement := 1
var stack []*StackElement
for readingCallers {
callerIncrement += 1
caller, file, line, ok := runtime.Caller(callerIncrement)
if !ok {
readingCallers = false
} else {
funcName := ""
if function := runtime.FuncForPC(caller); function != nil {
funcName = function.Name()
}
stack = append(stack, &StackElement{
File: file,
FunctionName: funcName,
Line: line,
})
s.Stack = &stack
}
}
}
func (s *ErrorWithStacktrace) Format() string {
if s == nil || s.Stack == nil || len(*s.Stack) == 0 {
return "[no stack trace]"
}
out := ""
lineSep := osdep.GetLineSep()
for i, se := range *s.Stack {
out += fmt.Sprintf("%7d | %s:%d%s %s%s", i, se.File, se.Line, lineSep, se.FunctionName, lineSep)
}
return out
}
func (s *ErrorWithStacktrace) Stacktrace() *[]*StackElement {
return s.Stack
}
func (r *ErrorReporter) New(err error) *ErrorWithStacktrace {
s := &ErrorWithStacktrace{error: err, ErrorCode: NoStatusCode}
s.build(r.EnableStacktraces)
return s
}
func (r *ErrorReporter) NewWithErrorCode(errorCode int, err error) *ErrorWithStacktrace {
s := &ErrorWithStacktrace{error: err, ErrorCode: errorCode}
s.build(r.EnableStacktraces)
return s
}
func New(enableStacktraces bool) *ErrorReporter {
return &ErrorReporter{EnableStacktraces: enableStacktraces}
}