package log import ( "fmt" "io" "runtime/debug" "time" ) // Formatter records log entries. type Formatter interface { Format(writer io.Writer, level int, msg string, args []interface{}) } // TextFormatter is the default recorder used if one is unspecified when // creating a new Logger. type TextFormatter struct { name string itoaLevelMap map[int]string timeLabel string } // NewTextFormatter returns a new instance of TextFormatter. SetName // must be called befored using it. func NewTextFormatter(name string) *TextFormatter { timeLabel := KeyMap.Time + AssignmentChar levelLabel := Separator + KeyMap.Level + AssignmentChar messageLabel := Separator + KeyMap.Message + AssignmentChar nameLabel := Separator + KeyMap.Name + AssignmentChar pidLabel := Separator + KeyMap.PID + AssignmentChar var buildKV = func(level string) string { buf := pool.Get() defer pool.Put(buf) buf.WriteString(pidLabel) buf.WriteString(pidStr) //buf.WriteString(Separator) buf.WriteString(nameLabel) buf.WriteString(name) //buf.WriteString(Separator) buf.WriteString(levelLabel) buf.WriteString(level) //buf.WriteString(Separator) buf.WriteString(messageLabel) return buf.String() } itoaLevelMap := map[int]string{ LevelDebug: buildKV(LevelMap[LevelDebug]), LevelWarn: buildKV(LevelMap[LevelWarn]), LevelInfo: buildKV(LevelMap[LevelInfo]), LevelError: buildKV(LevelMap[LevelError]), LevelFatal: buildKV(LevelMap[LevelFatal]), } return &TextFormatter{itoaLevelMap: itoaLevelMap, name: name, timeLabel: timeLabel} } func (tf *TextFormatter) set(buf bufferWriter, key string, val interface{}) { buf.WriteString(Separator) buf.WriteString(key) buf.WriteString(AssignmentChar) if err, ok := val.(error); ok { buf.WriteString(err.Error()) buf.WriteRune('\n') buf.WriteString(string(debug.Stack())) return } buf.WriteString(fmt.Sprintf("%v", val)) } // Format records a log entry. func (tf *TextFormatter) Format(writer io.Writer, level int, msg string, args []interface{}) { buf := pool.Get() defer pool.Put(buf) buf.WriteString(tf.timeLabel) buf.WriteString(time.Now().Format(timeFormat)) buf.WriteString(tf.itoaLevelMap[level]) buf.WriteString(msg) var lenArgs = len(args) if lenArgs > 0 { if lenArgs == 1 { tf.set(buf, singleArgKey, args[0]) } else if lenArgs%2 == 0 { for i := 0; i < lenArgs; i += 2 { if key, ok := args[i].(string); ok { if key == "" { // show key is invalid tf.set(buf, badKeyAtIndex(i), args[i+1]) } else { tf.set(buf, key, args[i+1]) } } else { // show key is invalid tf.set(buf, badKeyAtIndex(i), args[i+1]) } } } else { tf.set(buf, warnImbalancedKey, args) } } buf.WriteRune('\n') buf.WriteTo(writer) }