1package errors
2
3import (
4	"fmt"
5	"log"
6	"runtime"
7	"strings"
8)
9
10var SkipLogging map[string]bool
11
12func init() {
13	SkipLogging = make(map[string]bool, 10)
14}
15
16type Error struct {
17	Errs  []error
18	Stack []byte
19}
20
21func Errorf(format string, args ...interface{}) error {
22	buf := make([]byte, 50000)
23	n := runtime.Stack(buf, true)
24	trace := make([]byte, n)
25	copy(trace, buf)
26	return &Error{
27		Errs:  []error{fmt.Errorf(format, args...)},
28		Stack: trace,
29	}
30}
31
32func Logf(level, format string, args ...interface{}) {
33	if SkipLogging[level] {
34		return
35	}
36	pc, _, line, ok := runtime.Caller(1)
37	if !ok {
38		log.Printf(format, args)
39		return
40	}
41	fn := runtime.FuncForPC(pc)
42	msg := fmt.Sprintf(format, args...)
43	log.Printf("%v (%v:%v): %v", level, fn.Name(), line, msg)
44}
45
46func (e *Error) Chain(err error) error {
47	e.Errs = append(e.Errs, err)
48	return e
49}
50
51func (e *Error) Error() string {
52	if e == nil {
53		return "Error <nil>"
54	} else if len(e.Errs) == 0 {
55		return fmt.Sprintf("%v\n%s", e.Errs, string(e.Stack))
56	} else if len(e.Errs) == 1 {
57		return fmt.Sprintf("%v\n%s", e.Errs[0], string(e.Stack))
58	} else {
59		errs := make([]string, 0, len(e.Errs))
60		for _, err := range e.Errs {
61			errs = append(errs, err.Error())
62		}
63		return fmt.Sprintf("{%v}\n%s", strings.Join(errs, ", "), string(e.Stack))
64	}
65}
66
67func (e *Error) String() string {
68	return e.Error()
69}
70
71type ErrorFmter func(a ...interface{}) error
72
73func NotFound(a ...interface{}) error {
74	// return fmt.Errorf("Key '%v' was not found.", a...)
75	return Errorf("Key was not found.")
76}
77
78func NotFoundInBucket(a ...interface{}) error {
79	return Errorf("Key, '%v', was not in bucket when expected.", a...)
80}
81
82func InvalidKey(a ...interface{}) error {
83	return Errorf("Key, '%v', is invalid, %s", a...)
84}
85
86func TSTError(a ...interface{}) error {
87	return Errorf("Internal TST error - "+a[0].(string), a[1:]...)
88}
89
90func NegativeSize(a ...interface{}) error {
91	return Errorf("Negative size")
92}
93
94func BpTreeError(a ...interface{}) error {
95	return Errorf("Internal B+ Tree error - "+a[0].(string), a[1:]...)
96}
97
98var Errors map[string]ErrorFmter = map[string]ErrorFmter{
99	"not-found":           NotFound,
100	"not-found-in-bucket": NotFoundInBucket,
101	"invalid-key":         InvalidKey,
102	"tst-error":           TSTError,
103	"negative-size":       NegativeSize,
104	"bptree-error":        BpTreeError,
105}
106