d28f005552
Fix limit for databases other than sqlite go mod tidy && go mod vendor Remove unneeded break statements Make everything work with the new xorm version Fix xorm logging Fix lint Fix redis init Fix using id field Fix database init for testing Change default database log level Add xorm logger Use const for postgres go mod tidy Merge branch 'master' into update/xorm # Conflicts: # go.mod # go.sum # vendor/modules.txt go mod vendor Fix loading fixtures for postgres Go mod vendor1 Update xorm to version 1 Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/323
177 lines
4.1 KiB
Go
177 lines
4.1 KiB
Go
package errors
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"path"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Frame represents a program counter inside a stack frame.
|
|
// For historical reasons if Frame is interpreted as a uintptr
|
|
// its value represents the program counter + 1.
|
|
type Frame uintptr
|
|
|
|
// pc returns the program counter for this frame;
|
|
// multiple frames may have the same PC value.
|
|
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
|
|
|
// file returns the full path to the file that contains the
|
|
// function for this Frame's pc.
|
|
func (f Frame) file() string {
|
|
fn := runtime.FuncForPC(f.pc())
|
|
if fn == nil {
|
|
return "unknown"
|
|
}
|
|
file, _ := fn.FileLine(f.pc())
|
|
return file
|
|
}
|
|
|
|
// line returns the line number of source code of the
|
|
// function for this Frame's pc.
|
|
func (f Frame) line() int {
|
|
fn := runtime.FuncForPC(f.pc())
|
|
if fn == nil {
|
|
return 0
|
|
}
|
|
_, line := fn.FileLine(f.pc())
|
|
return line
|
|
}
|
|
|
|
// name returns the name of this function, if known.
|
|
func (f Frame) name() string {
|
|
fn := runtime.FuncForPC(f.pc())
|
|
if fn == nil {
|
|
return "unknown"
|
|
}
|
|
return fn.Name()
|
|
}
|
|
|
|
// Format formats the frame according to the fmt.Formatter interface.
|
|
//
|
|
// %s source file
|
|
// %d source line
|
|
// %n function name
|
|
// %v equivalent to %s:%d
|
|
//
|
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
|
//
|
|
// %+s function name and path of source file relative to the compile time
|
|
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
|
// %+v equivalent to %+s:%d
|
|
func (f Frame) Format(s fmt.State, verb rune) {
|
|
switch verb {
|
|
case 's':
|
|
switch {
|
|
case s.Flag('+'):
|
|
io.WriteString(s, f.name())
|
|
io.WriteString(s, "\n\t")
|
|
io.WriteString(s, f.file())
|
|
default:
|
|
io.WriteString(s, path.Base(f.file()))
|
|
}
|
|
case 'd':
|
|
io.WriteString(s, strconv.Itoa(f.line()))
|
|
case 'n':
|
|
io.WriteString(s, funcname(f.name()))
|
|
case 'v':
|
|
f.Format(s, 's')
|
|
io.WriteString(s, ":")
|
|
f.Format(s, 'd')
|
|
}
|
|
}
|
|
|
|
// MarshalText formats a stacktrace Frame as a text string. The output is the
|
|
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
|
|
func (f Frame) MarshalText() ([]byte, error) {
|
|
name := f.name()
|
|
if name == "unknown" {
|
|
return []byte(name), nil
|
|
}
|
|
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
|
|
}
|
|
|
|
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
|
type StackTrace []Frame
|
|
|
|
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
|
//
|
|
// %s lists source files for each Frame in the stack
|
|
// %v lists the source file and line number for each Frame in the stack
|
|
//
|
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
|
//
|
|
// %+v Prints filename, function, and line number for each Frame in the stack.
|
|
func (st StackTrace) Format(s fmt.State, verb rune) {
|
|
switch verb {
|
|
case 'v':
|
|
switch {
|
|
case s.Flag('+'):
|
|
for _, f := range st {
|
|
io.WriteString(s, "\n")
|
|
f.Format(s, verb)
|
|
}
|
|
case s.Flag('#'):
|
|
fmt.Fprintf(s, "%#v", []Frame(st))
|
|
default:
|
|
st.formatSlice(s, verb)
|
|
}
|
|
case 's':
|
|
st.formatSlice(s, verb)
|
|
}
|
|
}
|
|
|
|
// formatSlice will format this StackTrace into the given buffer as a slice of
|
|
// Frame, only valid when called with '%s' or '%v'.
|
|
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
|
|
io.WriteString(s, "[")
|
|
for i, f := range st {
|
|
if i > 0 {
|
|
io.WriteString(s, " ")
|
|
}
|
|
f.Format(s, verb)
|
|
}
|
|
io.WriteString(s, "]")
|
|
}
|
|
|
|
// stack represents a stack of program counters.
|
|
type stack []uintptr
|
|
|
|
func (s *stack) Format(st fmt.State, verb rune) {
|
|
switch verb {
|
|
case 'v':
|
|
switch {
|
|
case st.Flag('+'):
|
|
for _, pc := range *s {
|
|
f := Frame(pc)
|
|
fmt.Fprintf(st, "\n%+v", f)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *stack) StackTrace() StackTrace {
|
|
f := make([]Frame, len(*s))
|
|
for i := 0; i < len(f); i++ {
|
|
f[i] = Frame((*s)[i])
|
|
}
|
|
return f
|
|
}
|
|
|
|
func callers() *stack {
|
|
const depth = 32
|
|
var pcs [depth]uintptr
|
|
n := runtime.Callers(3, pcs[:])
|
|
var st stack = pcs[0:n]
|
|
return &st
|
|
}
|
|
|
|
// funcname removes the path prefix component of a function's name reported by func.Name().
|
|
func funcname(name string) string {
|
|
i := strings.LastIndex(name, "/")
|
|
name = name[i+1:]
|
|
i = strings.Index(name, ".")
|
|
return name[i+1:]
|
|
}
|