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  }