1package txn
2
3import (
4	"bytes"
5	"fmt"
6	"sort"
7	"sync/atomic"
8
9	"github.com/10gen/llmgo/bson"
10)
11
12var (
13	debugEnabled bool
14	logger       log_Logger
15)
16
17type log_Logger interface {
18	Output(calldepth int, s string) error
19}
20
21// Specify the *log.Logger where logged messages should be sent to.
22func SetLogger(l log_Logger) {
23	logger = l
24}
25
26// SetDebug enables or disables debugging.
27func SetDebug(debug bool) {
28	debugEnabled = debug
29}
30
31var ErrChaos = fmt.Errorf("interrupted by chaos")
32
33var debugId uint32
34
35func debugPrefix() string {
36	d := atomic.AddUint32(&debugId, 1) - 1
37	s := make([]byte, 0, 10)
38	for i := uint(0); i < 8; i++ {
39		s = append(s, "abcdefghijklmnop"[(d>>(4*i))&0xf])
40		if d>>(4*(i+1)) == 0 {
41			break
42		}
43	}
44	s = append(s, ')', ' ')
45	return string(s)
46}
47
48func logf(format string, args ...interface{}) {
49	if logger != nil {
50		logger.Output(2, fmt.Sprintf(format, argsForLog(args)...))
51	}
52}
53
54func debugf(format string, args ...interface{}) {
55	if debugEnabled && logger != nil {
56		logger.Output(2, fmt.Sprintf(format, argsForLog(args)...))
57	}
58}
59
60func argsForLog(args []interface{}) []interface{} {
61	for i, arg := range args {
62		switch v := arg.(type) {
63		case bson.ObjectId:
64			args[i] = v.Hex()
65		case []bson.ObjectId:
66			lst := make([]string, len(v))
67			for j, id := range v {
68				lst[j] = id.Hex()
69			}
70			args[i] = lst
71		case map[docKey][]bson.ObjectId:
72			buf := &bytes.Buffer{}
73			var dkeys docKeys
74			for dkey := range v {
75				dkeys = append(dkeys, dkey)
76			}
77			sort.Sort(dkeys)
78			for i, dkey := range dkeys {
79				if i > 0 {
80					buf.WriteByte(' ')
81				}
82				buf.WriteString(fmt.Sprintf("%v: {", dkey))
83				for j, id := range v[dkey] {
84					if j > 0 {
85						buf.WriteByte(' ')
86					}
87					buf.WriteString(id.Hex())
88				}
89				buf.WriteByte('}')
90			}
91			args[i] = buf.String()
92		case map[docKey][]int64:
93			buf := &bytes.Buffer{}
94			var dkeys docKeys
95			for dkey := range v {
96				dkeys = append(dkeys, dkey)
97			}
98			sort.Sort(dkeys)
99			for i, dkey := range dkeys {
100				if i > 0 {
101					buf.WriteByte(' ')
102				}
103				buf.WriteString(fmt.Sprintf("%v: %v", dkey, v[dkey]))
104			}
105			args[i] = buf.String()
106		}
107	}
108	return args
109}
110