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  }