github.com/shoshinnikita/budget-manager@v0.7.1-0.20220131195411-8c46ff1c6778/internal/logger/dev_format.go (about)

     1  package logger
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"sort"
     8  
     9  	"github.com/fatih/color"
    10  	"github.com/sirupsen/logrus"
    11  
    12  	"github.com/ShoshinNikita/budget-manager/internal/pkg/caller"
    13  )
    14  
    15  // {year}-{month}-{day} {hour}:{minute}:{second}
    16  const timeLayout = "2006-01-02 15:04:05"
    17  
    18  // devFormatter is used as a log formatter in the developer mode
    19  type devFormatter struct{}
    20  
    21  var _ logrus.Formatter = devFormatter{}
    22  
    23  // Format formats '*logrus.Entry'
    24  func (devFormatter) Format(entry *logrus.Entry) ([]byte, error) {
    25  	buff := &bytes.Buffer{}
    26  	if entry.Buffer != nil {
    27  		buff = entry.Buffer
    28  	}
    29  
    30  	// Time
    31  	buff.WriteString(color.HiGreenString(entry.Time.Format(timeLayout)))
    32  	buff.WriteByte(' ')
    33  
    34  	// Level
    35  	buff.Write(logLevelToString(entry.Level))
    36  	buff.WriteByte(' ')
    37  
    38  	// Message
    39  	buff.WriteString(entry.Message)
    40  	buff.WriteByte(' ')
    41  
    42  	// Fields
    43  
    44  	// Add the caller to fields
    45  	if entry.HasCaller() {
    46  		entry.Data["func"] = caller.FormatCaller(entry.Caller.Func)
    47  	}
    48  
    49  	// Sort field keys
    50  	keys := make([]string, 0, len(entry.Data))
    51  	for k := range entry.Data {
    52  		keys = append(keys, k)
    53  	}
    54  	sort.Strings(keys)
    55  
    56  	// Write
    57  	coloredPrintf := logLevelToPrintfFunction(entry.Level)
    58  	for i, k := range keys {
    59  		v := entry.Data[k]
    60  		if isEmptyString(v) {
    61  			v = `""`
    62  		}
    63  
    64  		buff.WriteString(coloredPrintf(k))
    65  		buff.WriteByte('=')
    66  		fmt.Fprint(buff, v)
    67  		if i+1 != len(keys) {
    68  			buff.WriteByte(' ')
    69  		}
    70  	}
    71  
    72  	buff.WriteByte('\n')
    73  	return buff.Bytes(), nil
    74  }
    75  
    76  // Ready to print colored log levels
    77  //
    78  //nolint:gochecknoglobals
    79  var (
    80  	coloredTraceLvl = []byte(color.HiMagentaString("[TRC]"))
    81  	coloredDebugLvl = []byte(color.HiMagentaString("[DBG]"))
    82  	coloredInfoLvl  = []byte(color.CyanString("[INF]"))
    83  	coloredWarnLvl  = []byte(color.YellowString("[WRN]"))
    84  	coloredErrLvl   = []byte(color.RedString("[ERR]"))
    85  	coloredPanicLvl = []byte(color.New(color.BgRed).Sprint("[PNC]"))
    86  	coloredFatalLvl = []byte(color.New(color.BgRed).Sprint("[FAT]"))
    87  )
    88  
    89  // logLevelToString converts logrus log level to colored string
    90  // It returns bytes for greater convenience
    91  func logLevelToString(lvl logrus.Level) []byte {
    92  	switch lvl {
    93  	case logrus.TraceLevel:
    94  		return coloredTraceLvl
    95  	case logrus.DebugLevel:
    96  		return coloredDebugLvl
    97  	case logrus.InfoLevel:
    98  		return coloredInfoLvl
    99  	case logrus.WarnLevel:
   100  		return coloredWarnLvl
   101  	case logrus.ErrorLevel:
   102  		return coloredErrLvl
   103  	case logrus.PanicLevel:
   104  		return coloredPanicLvl
   105  	case logrus.FatalLevel:
   106  		return coloredFatalLvl
   107  	default:
   108  		return []byte("[...]")
   109  	}
   110  }
   111  
   112  // logLevelToPrintfFunction returns a function to print colored output according to
   113  // passed logrus log level
   114  func logLevelToPrintfFunction(lvl logrus.Level) func(format string, a ...interface{}) string {
   115  	switch lvl {
   116  	case logrus.TraceLevel:
   117  		return color.YellowString
   118  	case logrus.DebugLevel:
   119  		return color.HiMagentaString
   120  	case logrus.InfoLevel:
   121  		return color.CyanString
   122  	case logrus.WarnLevel:
   123  		return color.YellowString
   124  	case logrus.ErrorLevel:
   125  		return color.RedString
   126  	case logrus.FatalLevel:
   127  		return color.New(color.BgRed).Sprintf
   128  	case logrus.PanicLevel:
   129  		return color.New(color.BgRed).Sprintf
   130  	default:
   131  		return color.New().Sprintf
   132  	}
   133  }
   134  
   135  func isEmptyString(i interface{}) bool {
   136  	v := reflect.ValueOf(i)
   137  	return v.Kind() == reflect.String && v.String() == ""
   138  }