-
-
Notifications
You must be signed in to change notification settings - Fork 49
/
debug.go
137 lines (118 loc) · 3.35 KB
/
debug.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package neffos
import (
"log"
"os"
"reflect"
)
var debugPrinter interface{}
// EnableDebug enables debug and optionally
// sets a custom printer to print out debug messages.
// The "printer" can be any compatible printer such as
// the standard `log.Logger` or a custom one like the `kataras/golog`.
//
// A "printer" is compatible when it contains AT LEAST ONE of the following methods:
// Debugf(string, ...interface{}) or
// Logf(string, ...interface{}) or
// Printf(string, ...interface{})
//
// If EnableDebug is called but the "printer" value is nil
// then neffos will print debug messages through a new log.Logger prefixed with "| neffos |".
//
// Note that neffos, currently, uses debug mode only on the build state of the events.
// Therefore enabling the debugger has zero performance cost on up-and-running servers and clients.
//
// There is no way to disable the debug mode on serve-time.
func EnableDebug(printer interface{}) {
if debugEnabled() {
Debugf("debug mode is already set")
return
}
if _, boolean := printer.(bool); boolean {
// if for some reason by accident EnableDebug(true) instead of a printer value.
printer = nil
}
if printer == nil {
logger := log.New(os.Stderr, "| neffos | ", 0)
printer = logger
logger.Println("debug mode is set")
}
debugPrinter = printer
}
type (
debugfer interface {
Debugf(string, ...interface{})
}
logfer interface {
Logf(string, ...interface{})
}
printfer interface {
Printf(string, ...interface{})
}
)
func debugEnabled() bool {
return debugPrinter != nil
}
// Debugf prints debug messages to the printer defined on `EnableDebug`.
// Runs only on debug mode.
func Debugf(format string, args ...interface{}) {
if !debugEnabled() {
return
}
if len(args) == 1 {
// handles:
// Debugf("format", func() dargs {
// time-consumed action that should run only on debug.
// })
if onDebugWithArgs, ok := args[0].(func() dargs); ok {
args = onDebugWithArgs()
}
}
switch printer := debugPrinter.(type) {
case debugfer:
printer.Debugf(format, args...)
case logfer:
printer.Logf(format, args...)
case printfer:
printer.Printf(format, args...)
default:
panic("unsported debug printer")
}
}
type dargs []interface{}
// DebugEach prints debug messages for each of "mapOrSlice" elements
// to the printer defined on `EnableDebug`.
// Runs only on debug mode.
// Usage:
//
// DebugEach(staticFields, func(idx int, f reflect.Value) {
// fval := f.Interface()
// Debugf("field [%s.%s] will be automatically re-filled with [%T(%s)]", typ.Name(), typ.Field(idx).Name, fval, fval)
// })
func DebugEach(mapOrSlice interface{}, onDebugVisitor interface{}) {
if !debugEnabled() || onDebugVisitor == nil {
return
}
visitor := reflect.ValueOf(onDebugVisitor)
visitorTyp := visitor.Type()
if visitorTyp.Kind() != reflect.Func {
return
}
userNumIn := visitorTyp.NumIn()
v := reflect.ValueOf(mapOrSlice)
switch v.Kind() {
case reflect.Map:
for ranger := v.MapRange(); ranger.Next(); {
in := make([]reflect.Value, userNumIn)
in[0] = ranger.Key()
if userNumIn > 1 {
// assume both key and value are expected.
in[1] = ranger.Value()
}
// note that we don't make any further checks here, it's only for internal
// use and I want to panic in my tests if I didn't expect the correct values.
visitor.Call(in)
}
case reflect.Slice:
// TODO: whenever I need this.
}
}