github.com/devstream-io/devstream@v0.13.3/internal/log/wrapper.go (about) 1 package log 2 3 import ( 4 "bytes" 5 "fmt" 6 "runtime" 7 8 "github.com/sirupsen/logrus" 9 "gopkg.in/gookit/color.v1" 10 ) 11 12 const ( 13 DEBUG = "[DEBUG] " 14 WARN = "[WARN] " 15 INFO = "[INFO] " 16 SUCCESS = "[SUCCESS] " 17 ERROR = "[ERROR] " 18 FATAL = "[FATAL] " 19 ) 20 21 // ROOTCALLER should be main proc 22 const ROOTCALLER = "main.main" 23 24 // REMOVELEVEL logrus stack level is 9, should be removed from stack trace 25 const REMOVELEVEL = 10 26 27 type CliLoggerFormatter struct { 28 level logrus.Level 29 showType string 30 formatLevelName string 31 prefix string 32 } 33 34 // Format implement Format interface to output custom log 35 func (m *CliLoggerFormatter) Format(entry *logrus.Entry) ([]byte, error) { 36 var b *bytes.Buffer 37 if entry.Buffer != nil { 38 b = entry.Buffer 39 } else { 40 b = &bytes.Buffer{} 41 } 42 43 m.levelPrintRender() 44 45 timestamp := entry.Time.Format("2006-01-02 15:04:05") 46 47 if m.level == logrus.ErrorLevel && logrus.GetLevel() == logrus.DebugLevel { 48 entry.Message = addCallStackIgnoreLogrus(entry.Message) 49 } 50 51 newLog := fmt.Sprintf("%s %s %s %s\n", timestamp, m.prefix, m.formatLevelName, entry.Message) 52 53 _, err := b.WriteString(newLog) 54 if err != nil { 55 return nil, err 56 } 57 return b.Bytes(), nil 58 } 59 60 // levelPrintRender render symbo and level according to type 61 func (m *CliLoggerFormatter) levelPrintRender() { 62 switch m.showType { 63 case "debug": 64 m.level = logrus.DebugLevel 65 m.formatLevelName = color.Blue.Render(DEBUG) 66 m.prefix = color.Blue.Render(normal.Debug) 67 case "info": 68 m.level = logrus.InfoLevel 69 m.formatLevelName = color.FgLightBlue.Render(INFO) 70 m.prefix = color.FgLightBlue.Render(normal.Info) 71 case "warn": 72 m.level = logrus.WarnLevel 73 m.formatLevelName = color.Yellow.Render(WARN) 74 m.prefix = color.Yellow.Render(normal.Warn) 75 case "error": 76 m.level = logrus.ErrorLevel 77 m.formatLevelName = color.BgRed.Render(ERROR) 78 m.prefix = color.Red.Render(normal.Error) 79 case "fatal": 80 m.level = logrus.FatalLevel 81 m.formatLevelName = color.BgRed.Render(FATAL) 82 m.prefix = color.Red.Render(normal.Fatal) 83 case "success": 84 m.level = logrus.InfoLevel 85 m.formatLevelName = color.Green.Render(SUCCESS) 86 m.prefix = color.Green.Render(normal.Success) 87 } 88 } 89 90 type SeparatorFormatter struct{} 91 92 // Format implement Format interface to output custom log 93 func (s *SeparatorFormatter) Format(entry *logrus.Entry) ([]byte, error) { 94 var b *bytes.Buffer 95 if entry.Buffer != nil { 96 b = entry.Buffer 97 } else { 98 b = &bytes.Buffer{} 99 } 100 101 timestamp := entry.Time.Format("2006-01-02 15:04:05") 102 newLog := fmt.Sprintf("%s %s %s %s\n", 103 timestamp, 104 color.Blue.Render(normal.Info), 105 color.Blue.Render(INFO), 106 color.Blue.Render(fmt.Sprintf("%s %s %s", "-------------------- [ ", entry.Message, " ] --------------------"))) 107 108 _, err := b.WriteString(newLog) 109 if err != nil { 110 return nil, err 111 } 112 return b.Bytes(), nil 113 } 114 115 // addCallStackIgnoreLogrus add call stack to log message without logrus stack 116 func addCallStackIgnoreLogrus(rawMessage string) string { 117 stackMessage := rawMessage 118 for i := REMOVELEVEL; ; i++ { 119 pc, file, line, _ := runtime.Caller(i) 120 stackMessage = stackMessage + "\n -- " + file + fmt.Sprintf(" %d", line) 121 entrance := runtime.FuncForPC(pc).Name() 122 if entrance == ROOTCALLER || entrance == "" { 123 break 124 } 125 } 126 return stackMessage 127 }