github.com/Aoi-hosizora/ahlib-more@v1.5.1-0.20230404072844-256112befaf6/xlogrus/xlogrus_test.go (about)

     1  package xlogrus
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/Aoi-hosizora/ahlib-more/xrotation"
     6  	"github.com/Aoi-hosizora/ahlib/xtesting"
     7  	"github.com/sirupsen/logrus"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"runtime"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  )
    16  
    17  func TestSimpleFormatter(t *testing.T) {
    18  	l := logrus.New()
    19  	l.SetLevel(logrus.TraceLevel)
    20  	sb := &strings.Builder{}
    21  	l.SetOutput(io.MultiWriter(os.Stdout, sb))
    22  
    23  	d := time.Date(2021, 12, 29, 18, 16, 13, 0, time.FixedZone("", 8*60*60))
    24  	for _, tc := range []struct {
    25  		giveFmt    *SimpleFormatter
    26  		giveReport bool
    27  		giveFn     func(l *logrus.Entry)
    28  		want       string
    29  	}{
    30  		{NewSimpleFormatter(), false, func(l *logrus.Entry) { l.Trace("test") },
    31  			"\x1b[37mTRAC\x1b[0m [2021-12-29T18:16:13+08:00] test\n"},
    32  		{NewSimpleFormatter(WithTimestampFormat("")), false, func(l *logrus.Entry) { l.Buffer = nil; l.Debug("test") },
    33  			"\x1b[37mDEBU\x1b[0m [2021-12-29T18:16:13+08:00] test\n"},
    34  		{NewSimpleFormatter(WithTimestampFormat("2006-01-02 15:04:05")), false, func(l *logrus.Entry) { l.Info("test") },
    35  			"\x1b[34mINFO\x1b[0m [2021-12-29 18:16:13] test\n"},
    36  		{NewSimpleFormatter(WithTimeLocation(time.UTC)), false, func(l *logrus.Entry) { l.Warn("test") },
    37  			"\x1b[33mWARN\x1b[0m [2021-12-29T10:16:13Z] test\n"},
    38  		{NewSimpleFormatter(WithTimeLocation(time.FixedZone("", -2*60*60))), false, func(l *logrus.Entry) { l.Warn("test") },
    39  			"\x1b[33mWARN\x1b[0m [2021-12-29T08:16:13-02:00] test\n"},
    40  		{NewSimpleFormatter(WithDisableColor(false)), false, func(l *logrus.Entry) { l.Error("test") },
    41  			"\x1b[31mERRO\x1b[0m [2021-12-29T18:16:13+08:00] test\n"},
    42  		{NewSimpleFormatter(WithTimestampFormat("2006-01-02"), WithDisableColor(true), WithTimeLocation(time.Local)), false, func(l *logrus.Entry) { l.Panic("test") },
    43  			"PANI [2021-12-29] test\n"},
    44  
    45  		{NewSimpleFormatter(), true, func(l *logrus.Entry) { l.Trace("test") },
    46  			"\x1b[37mTRAC\x1b[0m [2021-12-29T18:16:13+08:00] \x1b[2mxlogrus_test.go:45 xlogrus.TestSimpleFormatter.func8()\x1b[0m > test\n"},
    47  		{NewSimpleFormatter(WithCallerFormatter(func(*runtime.Frame) (string, string) { return "", "" })), true, func(l *logrus.Entry) { l.Debug("test") },
    48  			"\x1b[37mDEBU\x1b[0m [2021-12-29T18:16:13+08:00] test\n"},
    49  		{NewSimpleFormatter(WithCallerFormatter(func(*runtime.Frame) (string, string) { return "", "fn()" }), WithDisableColor(true)), true, func(l *logrus.Entry) { l.Info("test") },
    50  			"INFO [2021-12-29T18:16:13+08:00] fn() > test\n"},
    51  		{NewSimpleFormatter(WithCallerFormatter(func(*runtime.Frame) (string, string) { return "aaa.go:123", "fff()" })), true, func(l *logrus.Entry) { l.Warn("test") },
    52  			"\x1b[33mWARN\x1b[0m [2021-12-29T18:16:13+08:00] \x1b[2maaa.go:123 fff()\x1b[0m > test\n"},
    53  
    54  		{NewSimpleFormatter(WithLevelFormatter(func(l logrus.Level) string { return l.String() })), false, func(l *logrus.Entry) { l.Trace("test") },
    55  			"\x1b[37mtrace\x1b[0m [2021-12-29T18:16:13+08:00] test\n"},
    56  		{NewSimpleFormatter(WithLevelFormatter(func(l logrus.Level) string { return "" })), false, func(l *logrus.Entry) { l.Debug("test") },
    57  			"\x1b[37m\x1b[0m [2021-12-29T18:16:13+08:00] test\n"},
    58  		{NewSimpleFormatter(WithLevelFormatter(func(l logrus.Level) string { return l.String()[:1] })), false, func(l *logrus.Entry) { l.Info("test") },
    59  			"\x1b[34mi\x1b[0m [2021-12-29T18:16:13+08:00] test\n"},
    60  		{NewSimpleFormatter(WithLevelFormatter(func(l logrus.Level) string { return strings.ToUpper(l.String())[:1] }), WithDisableColor(true)), false, func(l *logrus.Entry) { l.Error("test") },
    61  			"E [2021-12-29T18:16:13+08:00] test\n"},
    62  
    63  		{NewSimpleFormatter(WithMessageFormatter(func(l, t, c, m string) string { return fmt.Sprintf("%s %s: %s\n", t, l, m) }), WithTimestampFormat("2006-01-02 15:04:05")), false, func(l *logrus.Entry) { l.Trace("test") },
    64  			"2021-12-29 18:16:13 \x1b[37mTRAC\x1b[0m: test\n"},
    65  		{NewSimpleFormatter(WithMessageFormatter(func(l, t, c, m string) string { return "" })), false, func(l *logrus.Entry) { l.Debug("test") },
    66  			""},
    67  		{NewSimpleFormatter(WithMessageFormatter(func(l, t, c, m string) string { return fmt.Sprintf("[%s] [%s] %s\n", t, l, m) }), WithDisableColor(true)), false, func(l *logrus.Entry) { l.Info("test") },
    68  			"[2021-12-29T18:16:13+08:00] [INFO] test\n"},
    69  		{NewSimpleFormatter(WithMessageFormatter(func(l, t, c, m string) string { return fmt.Sprintf("%s[%s] %s\n", l, t, m) }), WithLevelFormatter(func(l logrus.Level) string { return strings.ToUpper(l.String())[:1] })), false, func(l *logrus.Entry) { l.Warn("test") },
    70  			"\x1b[33mW\x1b[0m[2021-12-29T18:16:13+08:00] test\n"},
    71  	} {
    72  		l.SetFormatter(tc.giveFmt)
    73  		l.SetReportCaller(tc.giveReport)
    74  		sb.Reset()
    75  
    76  		entry := l.WithTime(d).WithField("key", "value")
    77  		func() {
    78  			defer func() { recover() }()
    79  			tc.giveFn(entry)
    80  		}()
    81  		xtesting.Equal(t, sb.String(), tc.want)
    82  	}
    83  }
    84  
    85  func TestLogrusFormatters(t *testing.T) {
    86  	l := logrus.New()
    87  	l.SetLevel(logrus.TraceLevel)
    88  	sb := &strings.Builder{}
    89  	l.SetOutput(io.MultiWriter(os.Stdout, sb))
    90  
    91  	d := time.Date(2022, 1, 20, 14, 56, 20, 123456789, time.Local)
    92  	for _, tc := range []struct {
    93  		giveFmt    logrus.Formatter
    94  		giveFunc   func(*logrus.Entry, ...interface{})
    95  		giveFields logrus.Fields
    96  		giveMsg    string
    97  		giveReport bool
    98  		want       string
    99  	}{
   100  		{RFC3339JsonFormatter(), (*logrus.Entry).Debug, logrus.Fields{}, "hello world 1", false,
   101  			`{"@@time":"2022-01-20T14:56:20.123456789+08:00","@level":"debug","@message":"hello world 1","entries":{}}`},
   102  		{RFC3339JsonFormatter(), (*logrus.Entry).Info, logrus.Fields{"key": "v"}, "hello world 2", false,
   103  			`{"@@time":"2022-01-20T14:56:20.123456789+08:00","@level":"info","@message":"hello world 2","entries":{"key":"v"}}`},
   104  		{RFC3339JsonFormatter(), (*logrus.Entry).Warn, logrus.Fields{"empty": ""}, "hello world 3", false,
   105  			`{"@@time":"2022-01-20T14:56:20.123456789+08:00","@level":"warning","@message":"hello world 3","entries":{"empty":""}}`},
   106  		{RFC3339JsonFormatter(), (*logrus.Entry).Error, logrus.Fields{"i": 123, "f": 3.14}, "hello world 4", true,
   107  			`{"@@time":"2022-01-20T14:56:20.123456789+08:00","@level":"error","@message":"hello world 4","entries":{"f":3.14,"i":123},`},
   108  
   109  		{RFC3339ColoredTextFormatter(), (*logrus.Entry).Debug, logrus.Fields{}, "hello world 1", false, "\x1b[37mDEBU\x1b[0m[2022-01-20T14:56:20+08:00] hello world 1"},
   110  		{RFC3339ColoredTextFormatter(), (*logrus.Entry).Info, logrus.Fields{"key": "v"}, "hello world 2", false, "\x1b[36mINFO\x1b[0m[2022-01-20T14:56:20+08:00] hello world 2                                 \x1b[36mkey\x1b[0m=\"v\""},
   111  		{RFC3339ColoredTextFormatter(), (*logrus.Entry).Warn, logrus.Fields{"empty": ""}, "hello world 3", false, "\x1b[33mWARN\x1b[0m[2022-01-20T14:56:20+08:00] hello world 3                                 \x1b[33mempty\x1b[0m=\"\""},
   112  		{RFC3339ColoredTextFormatter(), (*logrus.Entry).Error, logrus.Fields{"i": 123, "f": 3.14}, "hello world 4", false, "\x1b[31mERRO\x1b[0m[2022-01-20T14:56:20+08:00] hello world 4                                 \x1b[31mf\x1b[0m=\"3.14\" \x1b[31mi\x1b[0m=\"123\""},
   113  	} {
   114  		t.Run(tc.giveMsg, func(t *testing.T) {
   115  			l.SetFormatter(tc.giveFmt)
   116  			l.SetReportCaller(tc.giveReport)
   117  
   118  			sb.Reset()
   119  			entry := l.WithTime(d).WithFields(tc.giveFields)
   120  			tc.giveFunc(entry, tc.giveMsg)
   121  			l.SetReportCaller(false)
   122  			xtesting.Equal(t, sb.String()[:len(tc.want)], tc.want)
   123  		})
   124  	}
   125  
   126  	t.Run("caller", func(t *testing.T) {
   127  		entry := l.WithTime(d)
   128  		entry.Level = logrus.DebugLevel
   129  		entry.Message = "xxx"
   130  		entry.Caller = &runtime.Frame{
   131  			Function: "github.com/aaa/bbb.ccc.ddd",
   132  			File:     "aaa/bbb/ccc.go",
   133  			Line:     99,
   134  		}
   135  		l.SetReportCaller(true)
   136  		entry.Logger = l
   137  
   138  		// 1.
   139  		fmt1 := RFC3339JsonFormatter()
   140  		bs, err := fmt1.Format(entry)
   141  		_, _ = os.Stdout.Write(bs)
   142  		xtesting.Nil(t, err)
   143  		xtesting.Equal(t, string(bs), "{\"@@time\":\"2022-01-20T14:56:20.123456789+08:00\",\"@level\":\"debug\",\"@message\":\"xxx\",\"entries\":{},\"file\":\"aaa/bbb/ccc.go:99\",\"function\":\"github.com/aaa/bbb.ccc.ddd\"}\n")
   144  
   145  		// 2.
   146  		fmt2 := RFC3339ColoredTextFormatter()
   147  		bs, err = fmt2.Format(entry)
   148  		_, _ = os.Stdout.Write(bs)
   149  		xtesting.Nil(t, err)
   150  		xtesting.Equal(t, string(bs), "\x1b[37mDEBU\x1b[0m[2022-01-20T14:56:20+08:00]ccc.go:99 bbb.ccc.ddd() xxx                                          \n")
   151  	})
   152  }
   153  
   154  func TestRotationHook(t *testing.T) {
   155  	l := logrus.New()
   156  	l.SetLevel(logrus.TraceLevel)
   157  	l.SetFormatter(&logrus.TextFormatter{FullTimestamp: true, TimestampFormat: time.RFC3339, ForceColors: true})
   158  	l.SetOutput(os.Stdout)
   159  
   160  	type Os = []RotationHookOption
   161  	rl, err := xrotation.New("logger.log")
   162  	xtesting.Nil(t, err)
   163  	rl2, err := xrotation.New("console.log")
   164  	xtesting.Nil(t, err)
   165  
   166  	for _, tc := range []struct {
   167  		giveRotation *xrotation.RotationLogger
   168  		giveOptions  Os
   169  		giveFn       func(l *logrus.Entry)
   170  		wantPanic    bool
   171  		wantLevels   []logrus.Level
   172  		wantFilename string
   173  		wantContent  string
   174  	}{
   175  		{nil, Os{}, nil, true, nil, "", ""},
   176  		{nil, Os{WithRotateLevel(logrus.TraceLevel)}, nil, true, nil, "", ""},
   177  		{rl, Os{WithRotateLevel(logrus.TraceLevel)}, func(l *logrus.Entry) { l.Trace("test") },
   178  			false, logrus.AllLevels, "logger.log", "{\"key\":\"value\",\"level\":\"trace\",\"msg\":\"test\",\"time\":\"2021-12-29T18:16:13+08:00\"}\n"},
   179  		{rl2, Os{WithRotateLevel(logrus.DebugLevel), WithRotateFormatter(&logrus.JSONFormatter{})}, func(l *logrus.Entry) { l.Debug("test") },
   180  			false, logrus.AllLevels[:logrus.DebugLevel+1], "console.log", "{\"key\":\"value\",\"level\":\"debug\",\"msg\":\"test\",\"time\":\"2021-12-29T18:16:13+08:00\"}\n"},
   181  		{rl, Os{WithRotateFormatter(&logrus.TextFormatter{})}, func(l *logrus.Entry) { l.Info("test") },
   182  			false, logrus.AllLevels[:logrus.WarnLevel+1], "", ""},
   183  		{rl, Os{WithRotateFormatter(&logrus.TextFormatter{DisableColors: true})}, func(l *logrus.Entry) { l.Warn("test") },
   184  			false, logrus.AllLevels[:logrus.WarnLevel+1], "logger.log", "time=\"2021-12-29T18:16:13+08:00\" level=warning msg=test key=value\n"},
   185  		{rl2, Os{WithRotateLevel(99999), WithRotateFormatter(NewSimpleFormatter(WithDisableColor(true)))}, func(l *logrus.Entry) { l.Panic("test") },
   186  			false, []logrus.Level{logrus.PanicLevel}, "console.log", "PANI [2021-12-29T18:16:13+08:00] test\n"},
   187  	} {
   188  		if tc.wantPanic {
   189  			xtesting.Panic(t, func() { NewRotationHook(tc.giveRotation, tc.giveOptions...) })
   190  			continue
   191  		}
   192  		hook := NewRotationHook(tc.giveRotation, tc.giveOptions...)
   193  		l.Hooks = logrus.LevelHooks{}
   194  		l.AddHook(hook)
   195  		xtesting.Equal(t, hook.Levels(), tc.wantLevels)
   196  		if tc.wantFilename != "" {
   197  			_ = os.Remove(tc.wantFilename)
   198  		}
   199  
   200  		entry := l.WithTime(time.Date(2021, 12, 29, 18, 16, 13, 0, time.Local)).WithField("key", "value")
   201  		func() {
   202  			defer func() { recover() }()
   203  			tc.giveFn(entry)
   204  		}()
   205  		_, err := os.Stat(tc.wantFilename)
   206  		if tc.wantFilename == "" {
   207  			xtesting.True(t, os.IsNotExist(err))
   208  		} else {
   209  			xtesting.Nil(t, err)
   210  			bs, err := ioutil.ReadFile(tc.wantFilename)
   211  			xtesting.Nil(t, err)
   212  			xtesting.Equal(t, string(bs), tc.wantContent)
   213  		}
   214  
   215  		if o := hook.rotation; o != nil {
   216  			xtesting.Nil(t, o.Close())
   217  		}
   218  		if tc.wantFilename != "" {
   219  			xtesting.Nil(t, os.Remove(tc.wantFilename))
   220  		}
   221  	}
   222  }