github.com/unionj-cloud/go-doudou@v1.3.8-0.20221011095552-0088008e5b31/toolkit/sqlext/logger/logger.go (about)

     1  package logger
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"github.com/ascarter/requestid"
     7  	"github.com/opentracing/opentracing-go"
     8  	"github.com/pkg/errors"
     9  	"github.com/rs/zerolog"
    10  	"github.com/uber/jaeger-client-go"
    11  	"github.com/unionj-cloud/go-doudou/toolkit/caller"
    12  	"github.com/unionj-cloud/go-doudou/toolkit/cast"
    13  	"github.com/unionj-cloud/go-doudou/toolkit/reflectutils"
    14  	"github.com/unionj-cloud/go-doudou/toolkit/stringutils"
    15  	"github.com/unionj-cloud/go-doudou/toolkit/zlogger"
    16  	"os"
    17  	"regexp"
    18  	"strings"
    19  )
    20  
    21  type SqlLogger struct {
    22  	Logger zerolog.Logger
    23  }
    24  
    25  func (receiver SqlLogger) Enable() bool {
    26  	return cast.ToBoolOrDefault(os.Getenv("GDD_SQL_LOG_ENABLE"), false)
    27  }
    28  
    29  func (receiver SqlLogger) Log(ctx context.Context, query string, args ...interface{}) {
    30  	if !receiver.Enable() {
    31  		return
    32  	}
    33  	receiver.LogWithErr(ctx, nil, nil, query, args...)
    34  }
    35  
    36  type SqlLoggerOption func(logger *SqlLogger)
    37  
    38  func WithLogger(logger zerolog.Logger) SqlLoggerOption {
    39  	return func(sqlLogger *SqlLogger) {
    40  		sqlLogger.Logger = logger
    41  	}
    42  }
    43  
    44  func NewSqlLogger(opts ...SqlLoggerOption) SqlLogger {
    45  	sqlLogger := SqlLogger{
    46  		Logger: zlogger.Logger,
    47  	}
    48  	for _, item := range opts {
    49  		item(&sqlLogger)
    50  	}
    51  	return sqlLogger
    52  }
    53  
    54  var limitre *regexp.Regexp
    55  
    56  func init() {
    57  	limitre = regexp.MustCompile(`limit '\d+'(,'\d+')?`)
    58  }
    59  
    60  func PopulatedSql(query string, args ...interface{}) string {
    61  	query = strings.Join(strings.Fields(query), " ")
    62  	copiedArgs := make([]interface{}, len(args))
    63  	copy(copiedArgs, args)
    64  	for i, arg := range copiedArgs {
    65  		if arg == nil {
    66  			continue
    67  		}
    68  		value := reflectutils.ValueOf(arg)
    69  		if value.IsValid() {
    70  			copiedArgs[i] = value.Interface()
    71  		}
    72  	}
    73  	str := strings.ReplaceAll(fmt.Sprintf(strings.ReplaceAll(query, "?", "'%v'"), copiedArgs...), "'<nil>'", "null")
    74  	if limitre.MatchString(str) {
    75  		str = limitre.ReplaceAllStringFunc(str, func(s string) string {
    76  			return strings.ReplaceAll(s, "'", "")
    77  		})
    78  	}
    79  	return str
    80  }
    81  
    82  func (receiver SqlLogger) LogWithErr(ctx context.Context, err error, hit *bool, query string, args ...interface{}) {
    83  	if !receiver.Enable() {
    84  		return
    85  	}
    86  	var sb strings.Builder
    87  	if reqId, ok := requestid.FromContext(ctx); ok && stringutils.IsNotEmpty(reqId) {
    88  		sb.WriteString(fmt.Sprintf("RequestID: %s\t", reqId))
    89  	}
    90  	span := opentracing.SpanFromContext(ctx)
    91  	if span != nil {
    92  		if jspan, ok := span.(*jaeger.Span); ok {
    93  			sb.WriteString(fmt.Sprintf("TraceID: %s\t", jspan.SpanContext().TraceID().String()))
    94  		} else {
    95  			sb.WriteString(fmt.Sprintf("TraceID: %s\t", span))
    96  		}
    97  	}
    98  	sb.WriteString(fmt.Sprintf("SQL: %s", PopulatedSql(query, args...)))
    99  	if hit != nil {
   100  		sb.WriteString(fmt.Sprintf("\tHIT: %t", *hit))
   101  	}
   102  	if err != nil {
   103  		sb.WriteString(fmt.Sprintf("\tERR: %s", errors.Wrap(err, caller.NewCaller().String())))
   104  	}
   105  	receiver.Logger.Info().Msgf(sb.String())
   106  }