package logger import ( "bytes" "encoding/json" "fmt" "github.com/fatih/color" ) var nextFormatID = 1 type IFormatter interface { Format(Entry) []byte NextColor() IFormatter Color() string } type formatterJSON struct{} func (f formatterJSON) Format(entry Entry) []byte { jsonEntry, err := json.Marshal(entry) if err != nil { return []byte(fmt.Sprintf("failed to marshal entry: %v: %+v\n", err, entry)) } return append(jsonEntry, []byte("\n")...) } func (f formatterJSON) NextColor() IFormatter { return f //do not select colors for JSON (only used in console) } func (f formatterJSON) Color() string { return "default" } func NewConsole() IFormatter { nextFormatID++ return formatterConsole{ id: nextFormatID, fg: 1, //color.FgWhite, bg: 0, //color.BgBlack, } } type formatterConsole struct { id int fg int //color.Attribute bg int //color.Attribute } func (f formatterConsole) Format(entry Entry) []byte { source := fmt.Sprintf("%s/%s:%d", entry.Caller.Package, entry.Caller.File, entry.Caller.Line) if len(source) > 40 { source = source[len(source)-40:] } buffer := bytes.NewBuffer(nil) red := color.New(color.FgRed).FprintfFunc() magenta := color.New(color.FgMagenta).FprintfFunc() yellow := color.New(color.FgYellow).FprintfFunc() green := color.New(color.FgGreen).FprintfFunc() cyan := color.New(color.FgCyan).FprintfFunc() cyan(buffer, entry.Timestamp.Format("2006-01-02 15:04:05")) levelString := fmt.Sprintf(" %5.5s", entry.Level) switch entry.Level { case LevelFatal: red(buffer, levelString) case LevelError: red(buffer, levelString) case LevelWarn: magenta(buffer, levelString) case LevelInfo: yellow(buffer, levelString) case LevelDebug: green(buffer, levelString) } cyan(buffer, fmt.Sprintf(" %-40.40s| ", source)) base := color.New(fgColors[colorNames[f.fg]], bgColors[colorNames[f.bg]]).FprintfFunc() base(buffer, entry.Message) if len(entry.Data) > 0 { jsonData, _ := json.Marshal(entry.Data) green(buffer, " "+string(jsonData)) } buffer.WriteString("\n") return buffer.Bytes() } func (f formatterConsole) WithForeground(fg color.Attribute) IFormatter { // f.fg = fg return f } func (f formatterConsole) WithBackground(bg color.Attribute) IFormatter { // f.bg = bg return f } func (f formatterConsole) Color() string { return colorNames[f.fg] + " on " + colorNames[f.bg] } var ( colorNames = []string{"black", "white", "red", "green", "yellow", "blue", "magenta", "cyan"} fgColors = map[string]color.Attribute{ "black": color.FgBlack, "white": color.FgWhite, "red": color.FgRed, "green": color.FgGreen, "yellow": color.FgYellow, "blue": color.FgBlue, "magenta": color.FgMagenta, "cyan": color.FgCyan, } bgColors = map[string]color.Attribute{ "black": color.BgBlack, "white": color.BgWhite, "red": color.BgRed, "green": color.BgGreen, "yellow": color.BgYellow, "blue": color.BgBlue, "magenta": color.BgMagenta, "cyan": color.BgCyan, } nextFg = 1 nextBg = 0 ) func (f formatterConsole) NextColor() IFormatter { for { nextFg++ if nextFg >= len(fgColors) { nextFg = 0 } if nextFg != nextBg { break } } nextFormatID++ f = formatterConsole{ id: nextFormatID, fg: nextFg, bg: nextBg, } return f }