diff --git a/logger.go b/logger.go index 4324a2e4..4506bcfe 100644 --- a/logger.go +++ b/logger.go @@ -1,119 +1 @@ package gorm - -import ( - "database/sql/driver" - "fmt" - "log" - "os" - "reflect" - "regexp" - "strconv" - "time" - "unicode" -) - -var ( - defaultLogger = Logger{log.New(os.Stdout, "\r\n", 0)} - sqlRegexp = regexp.MustCompile(`\?`) - numericPlaceHolderRegexp = regexp.MustCompile(`\$\d+`) -) - -func isPrintable(s string) bool { - for _, r := range s { - if !unicode.IsPrint(r) { - return false - } - } - return true -} - -var LogFormatter = func(values ...interface{}) (messages []interface{}) { - if len(values) > 1 { - var ( - sql string - formattedValues []string - level = values[0] - currentTime = "\n\033[33m[" + NowFunc().Format("2006-01-02 15:04:05") + "]\033[0m" - source = fmt.Sprintf("\033[35m(%v)\033[0m", values[1]) - ) - - messages = []interface{}{source, currentTime} - - if level == "sql" { - // duration - messages = append(messages, fmt.Sprintf(" \033[36;1m[%.2fms]\033[0m ", float64(values[2].(time.Duration).Nanoseconds()/1e4)/100.0)) - // sql - - for _, value := range values[4].([]interface{}) { - indirectValue := reflect.Indirect(reflect.ValueOf(value)) - if indirectValue.IsValid() { - value = indirectValue.Interface() - if t, ok := value.(time.Time); ok { - formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format("2006-01-02 15:04:05"))) - } else if b, ok := value.([]byte); ok { - if str := string(b); isPrintable(str) { - formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str)) - } else { - formattedValues = append(formattedValues, "''") - } - } else if r, ok := value.(driver.Valuer); ok { - if value, err := r.Value(); err == nil && value != nil { - formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value)) - } else { - formattedValues = append(formattedValues, "NULL") - } - } else { - formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value)) - } - } else { - formattedValues = append(formattedValues, "NULL") - } - } - - // differentiate between $n placeholders or else treat like ? - if numericPlaceHolderRegexp.MatchString(values[3].(string)) { - sql = values[3].(string) - for index, value := range formattedValues { - placeholder := fmt.Sprintf(`\$%d([^\d]|$)`, index+1) - sql = regexp.MustCompile(placeholder).ReplaceAllString(sql, value+"$1") - } - } else { - formattedValuesLength := len(formattedValues) - for index, value := range sqlRegexp.Split(values[3].(string), -1) { - sql += value - if index < formattedValuesLength { - sql += formattedValues[index] - } - } - } - - messages = append(messages, sql) - messages = append(messages, fmt.Sprintf(" \n\033[36;31m[%v]\033[0m ", strconv.FormatInt(values[5].(int64), 10)+" rows affected or returned ")) - } else { - messages = append(messages, "\033[31;1m") - messages = append(messages, values[2:]...) - messages = append(messages, "\033[0m") - } - } - - return -} - -type logger interface { - Print(v ...interface{}) -} - -// LogWriter log writer interface -type LogWriter interface { - Println(v ...interface{}) -} - -// Logger default logger -type Logger struct { - LogWriter -} - -// Print format & print log -func (logger Logger) Print(values ...interface{}) { - logger.Println(LogFormatter(values...)...) -} diff --git a/logger/formatter.go b/logger/formatter.go new file mode 100644 index 00000000..69ecb64a --- /dev/null +++ b/logger/formatter.go @@ -0,0 +1,88 @@ +package logger + +import ( + "database/sql/driver" + "fmt" + "reflect" + "regexp" + "strconv" + "time" + "unicode" +) + +var ( + sqlRegexp = regexp.MustCompile(`\?`) + numericPlaceHolderRegexp = regexp.MustCompile(`\$\d+`) +) + +func isPrintable(s string) bool { + for _, r := range s { + if !unicode.IsPrint(r) { + return false + } + } + return true +} + +func SQLFormatter(values ...interface{}) (messages []interface{}) { + if len(values) > 1 { + var ( + sql string + formattedValues []string + currentTime = time.Now().Format("2006-01-02 15:04:05") + ) + + messages = []interface{}{currentTime} + + // duration + messages = append(messages, fmt.Sprintf(" [%.2fms]", float64(values[0].(time.Duration).Nanoseconds()/1e4)/100.0)) + + for _, value := range values[2].([]interface{}) { + indirectValue := reflect.Indirect(reflect.ValueOf(value)) + if indirectValue.IsValid() { + value = indirectValue.Interface() + if t, ok := value.(time.Time); ok { + formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format("2006-01-02 15:04:05"))) + } else if b, ok := value.([]byte); ok { + if str := string(b); isPrintable(str) { + formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str)) + } else { + formattedValues = append(formattedValues, "''") + } + } else if r, ok := value.(driver.Valuer); ok { + if value, err := r.Value(); err == nil && value != nil { + formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value)) + } else { + formattedValues = append(formattedValues, "NULL") + } + } else { + formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value)) + } + } else { + formattedValues = append(formattedValues, "NULL") + } + } + + // differentiate between $n placeholders or else treat like ? + if numericPlaceHolderRegexp.MatchString(values[1].(string)) { + sql = values[1].(string) + for index, value := range formattedValues { + placeholder := fmt.Sprintf(`\$%d([^\d]|$)`, index+1) + sql = regexp.MustCompile(placeholder).ReplaceAllString(sql, value+"$1") + } + } else { + formattedValuesLength := len(formattedValues) + for index, value := range sqlRegexp.Split(values[1].(string), -1) { + sql += value + if index < formattedValuesLength { + sql += formattedValues[index] + } + } + } + + messages = append(messages, sql) + messages = append(messages, fmt.Sprintf(" \n[%v]", strconv.FormatInt(values[3].(int64), 10)+" rows affected or returned ")) + } + + return +} diff --git a/logger/logger.go b/logger/logger.go index 74eb10ac..52306253 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -1,9 +1,17 @@ package logger -import "os" +import ( + "fmt" + "log" + "os" +) // Interface logger interface type Interface interface { + SQL(data ...interface{}) + Info(data ...interface{}) + Warn(data ...interface{}) + Error(data ...interface{}) } // LogLevel log level @@ -12,9 +20,12 @@ type LogLevel int // DefaultLogLevel default log level var DefaultLogLevel LogLevel +// DefaultLogger default logger +var DefaultLogger = Logger{log.New(os.Stdout, "\r\n", 0)} + const ( // Info print SQL, warn messages and errors - Info LogLevel = 1 << iota + Info LogLevel = iota - 1 // Warn print warn messages and errors Warn // Error print errors @@ -33,3 +44,35 @@ func init() { DefaultLogLevel = Error } } + +// LogWriter log writer interface +type LogWriter interface { + Println(v ...interface{}) +} + +// Logger logger +type Logger struct { + LogWriter +} + +// SQL print SQL statements +func (logger Logger) SQL(data ...interface{}) { +} + +// Info print info +func (logger Logger) Info(message string, data ...interface{}) { + // TODO show file line number + logger.Println(fmt.Sprintf("[info] %v", fmt.Sprintf(message, data...))) +} + +// Warn print warn messages +func (logger Logger) Warn(message string, data ...interface{}) { + // TODO show file line number + logger.Println(fmt.Sprintf("[warn] %v", fmt.Sprintf(message, data...))) +} + +// Error print error messages +func (logger Logger) Error(message string, data ...interface{}) { + // TODO show file line number + logger.Println(fmt.Sprintf("[error] %v", fmt.Sprintf(message, data...))) +} diff --git a/main.go b/main.go index 138e1a12..af5285c9 100644 --- a/main.go +++ b/main.go @@ -18,8 +18,6 @@ type DB struct { // single db db SQLCommon blockGlobalUpdate bool - logMode int - logger logger search *search values map[string]interface{} @@ -696,8 +694,6 @@ func (s *DB) clone() *DB { db := &DB{ db: s.db, parent: s.parent, - logger: s.logger, - logMode: s.logMode, values: map[string]interface{}{}, Value: s.Value, Error: s.Error,