github.com/jxskiss/gopkg@v0.17.3/easy/log_debug.go (about) 1 package easy 2 3 import ( 4 "context" 5 "reflect" 6 "strings" 7 8 "github.com/davecgh/go-spew/spew" 9 ) 10 11 type stringerFunc func(v interface{}) string 12 13 /* 14 DEBUG is debug message logger which do nothing if debug level is not enabled (the default). 15 It gives best performance for production deployment by eliminating unnecessary 16 parameter evaluation and control flows. 17 18 DEBUG accepts very flexible arguments to help development, see the following examples: 19 20 // func() 21 DEBUG(func() { 22 logrus.Debug(something) 23 for _, item := range someSlice { 24 logrus.Debug(item) 25 } 26 }) 27 28 // logger from context with or without format 29 DEBUG(ctx, 1, 2, 3) 30 DEBUG(ctx, "a=%v b=%v c=%v", 1, 2, 3) 31 32 // log variables with or without format 33 DEBUG(1, 2, 3) 34 DEBUG("a=%v b=%v c=%v", 1, 2, 3) 35 36 // optionally a DebugLogger can be provided as the first parameter 37 logger := logrus.WithField("key", "dummy") 38 DEBUG(logger, "aa", 2, 3) 39 DEBUG(logger, "a=%v b=%v c=%v", "aa", 2, 3) 40 41 // or a function which returns a logger implements DebugLogger 42 logger := func() *logrus.Entry { ... } 43 DEBUG(logger, "aa", 2, 3) 44 DEBUG(logger, "a=%v b=%v c=%v", "aa", 2, 3) 45 46 // or a print function to print the log message 47 logger := logrus.Debugf 48 DEBUG(logger, "aa", 2, 3) 49 DEBUG(logger, "a=%v b=%v c=%v", "aa", 2, 3) 50 51 // non-basic-type values will be formatted using json 52 obj := &SomeStructType{Field1: "blah", Field2: 1234567, Field3: true} 53 DEBUG(logger, "obj=%v", obj) 54 */ 55 func DEBUG(args ...interface{}) { 56 stringer := JSON 57 logdebug(1, stringer, args...) 58 } 59 60 // DEBUGSkip is similar to DEBUG, but it has an extra skip param to skip stacktrace 61 // to get correct caller information. 62 // When you wrap functions in this package, you always want to use the functions 63 // which end with "Skip". 64 func DEBUGSkip(skip int, args ...interface{}) { 65 stringer := JSON 66 logdebug(skip+1, stringer, args...) 67 } 68 69 // PRETTY is similar to DEBUG, but it calls Pretty to format non-basic-type data. 70 func PRETTY(args ...interface{}) { 71 stringer := Pretty 72 logdebug(1, stringer, args...) 73 } 74 75 // PRETTYSkip is similar to PRETTY, but it has an extra skip param to skip stacktrace 76 // to get correct caller information. 77 // When you wrap functions in this package, you always want to use the functions 78 // which end with "Skip". 79 func PRETTYSkip(skip int, args ...interface{}) { 80 stringer := Pretty 81 logdebug(skip+1, stringer, args...) 82 } 83 84 // SPEW is similar to DEBUG, but it calls spew.Sprintf to format non-basic-type data. 85 func SPEW(args ...interface{}) { 86 stringer := func(v interface{}) string { return spew.Sprintf("%#v", v) } 87 logdebug(1, stringer, args...) 88 } 89 90 // SPEWSkip is similar to SPEW, but it has an extra skip param to skip stacktrace 91 // to get correct caller information. 92 // When you wrap functions in this package, you always want to use the functions 93 // which end with "Skip". 94 func SPEWSkip(skip int, args ...interface{}) { 95 stringer := func(v interface{}) string { return spew.Sprintf("%#v", v) } 96 logdebug(skip+1, stringer, args...) 97 } 98 99 // DUMP is similar to DEBUG, but it calls spew.Sdump to format non-basic-type data. 100 func DUMP(args ...interface{}) { 101 stringer := func(v interface{}) string { return spew.Sdump(v) } 102 logdebug(1, stringer, args...) 103 } 104 105 // DUMPSkip is similar to DUMP, but it has an extra skip param to skip stacktrace 106 // to get correct caller information. 107 // When you wrap functions in this package, you always want to use the functions 108 // which end with "Skip". 109 func DUMPSkip(skip int, args ...interface{}) { 110 stringer := func(v interface{}) string { return spew.Sdump(v) } 111 logdebug(skip+1, stringer, args...) 112 } 113 114 func logdebug(skip int, stringer stringerFunc, args ...interface{}) { 115 if _logcfg.EnableDebug == nil || !_logcfg.EnableDebug() { 116 return 117 } 118 var logger DebugLogger 119 if len(args) > 0 { 120 if arg0, ok := args[0].(func()); ok { 121 arg0() 122 return 123 } 124 logger, args = parseLogger(args) 125 } 126 if logger == nil { 127 logger = _logcfg.getLogger(nil) 128 } 129 outputDebugLog(skip+1, logger, stringer, args) 130 } 131 132 func outputDebugLog(skip int, logger DebugLogger, stringer stringerFunc, args []interface{}) { 133 caller, file, line := Caller(skip + 1) 134 callerPrefix := "[" + caller + "] " 135 if len(args) > 0 { 136 if format, ok := args[0].(string); ok && strings.IndexByte(format, '%') >= 0 { 137 logger.Debugf(callerPrefix+format, formatArgs(stringer, args[1:])...) 138 return 139 } 140 format := callerPrefix + "%v" + strings.Repeat(" %v", len(args)-1) 141 logger.Debugf(format, formatArgs(stringer, args)...) 142 } else { 143 logger.Debugf("======== %s#L%d - %s ========", file, line, caller) 144 } 145 } 146 147 var debugLoggerTyp = reflect.TypeOf((*DebugLogger)(nil)).Elem() 148 149 func parseLogger(args []interface{}) (DebugLogger, []interface{}) { 150 var logger DebugLogger 151 if arg0, ok := args[0].(DebugLogger); ok { 152 logger = arg0 153 args = args[1:] 154 return logger, args 155 } 156 157 switch arg0 := args[0].(type) { 158 case context.Context: 159 logger = _logcfg.getLogger(&arg0) 160 args = args[1:] 161 case func(string, ...interface{}): 162 logger = PrintFunc(arg0) 163 args = args[1:] 164 default: 165 arg0typ := reflect.TypeOf(arg0) 166 if arg0typ.Kind() == reflect.Func { 167 if arg0typ.NumIn() == 0 && arg0typ.NumOut() == 1 && 168 arg0typ.Out(0).Implements(debugLoggerTyp) { 169 out := reflect.ValueOf(arg0).Call(nil)[0] 170 logger = out.Interface().(DebugLogger) 171 } 172 args = args[1:] 173 } 174 } 175 return logger, args 176 }