github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/logutil/log_test.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package logutil 15 16 import ( 17 "bufio" 18 "bytes" 19 "context" 20 "fmt" 21 "io" 22 "os" 23 "runtime" 24 "strings" 25 "testing" 26 27 . "github.com/whtcorpsinc/check" 28 zaplog "github.com/whtcorpsinc/log" 29 log "github.com/sirupsen/logrus" 30 "go.uber.org/zap" 31 ) 32 33 const ( 34 logPattern = `\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d\.\d\d\d ([\w_%!$@.,+~-]+|\\.)+:\d+: \[(fatal|error|warning|info|debug)\] .*?\n` 35 // zapLogPatern is used to match the zap log format, such as the following log: 36 // [2020/02/13 15:56:05.385 +08:00] [INFO] [log_test.go:167] ["info message"] ["str key"=val] ["int key"=123] 37 zapLogPattern = `\[\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d.\d\d\d\ (\+|-)\d\d:\d\d\] \[(FATAL|ERROR|WARN|INFO|DEBUG)\] \[([\w_%!$@.,+~-]+|\\.)+:\d+\] \[.*\] (\[.*=.*\]).*\n` 38 // [2020/02/13 15:56:05.385 +08:00] [INFO] [log_test.go:167] ["info message"] ["str key"=val] ["int key"=123] 39 zapLogWithConnIDPattern = `\[\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d.\d\d\d\ (\+|-)\d\d:\d\d\] \[(FATAL|ERROR|WARN|INFO|DEBUG)\] \[([\w_%!$@.,+~-]+|\\.)+:\d+\] \[.*\] \[conn=.*\] (\[.*=.*\]).*\n` 40 // [2020/02/13 15:56:05.385 +08:00] [INFO] [log_test.go:167] ["info message"] ["str key"=val] ["int key"=123] 41 zapLogWithKeyValPattern = `\[\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d.\d\d\d\ (\+|-)\d\d:\d\d\] \[(FATAL|ERROR|WARN|INFO|DEBUG)\] \[([\w_%!$@.,+~-]+|\\.)+:\d+\] \[.*\] \[ctxKey=.*\] (\[.*=.*\]).*\n` 42 ) 43 44 var PrettyPrint = prettyPrint 45 46 func Test(t *testing.T) { 47 TestingT(t) 48 } 49 50 var _ = Suite(&testLogSuite{}) 51 52 type testLogSuite struct { 53 buf *bytes.Buffer 54 } 55 56 func (s *testLogSuite) SetUpSuite(c *C) { 57 s.buf = &bytes.Buffer{} 58 } 59 60 func (s *testLogSuite) SetUpTest(c *C) { 61 s.buf = &bytes.Buffer{} 62 } 63 64 func (s *testLogSuite) TestStringToLogLevel(c *C) { 65 c.Assert(stringToLogLevel("fatal"), Equals, log.FatalLevel) 66 c.Assert(stringToLogLevel("ERROR"), Equals, log.ErrorLevel) 67 c.Assert(stringToLogLevel("warn"), Equals, log.WarnLevel) 68 c.Assert(stringToLogLevel("warning"), Equals, log.WarnLevel) 69 c.Assert(stringToLogLevel("debug"), Equals, log.DebugLevel) 70 c.Assert(stringToLogLevel("info"), Equals, log.InfoLevel) 71 c.Assert(stringToLogLevel("whatever"), Equals, log.InfoLevel) 72 } 73 74 // TestLogging assure log format and log redirection works. 75 func (s *testLogSuite) TestLogging(c *C) { 76 conf := NewLogConfig("warn", DefaultLogFormat, "", NewFileLogConfig(0), false) 77 conf.File.Filename = "log_file" 78 c.Assert(InitLogger(conf), IsNil) 79 80 log.SetOutput(s.buf) 81 82 log.Infof("[this message should not be sent to buf]") 83 c.Assert(s.buf.Len(), Equals, 0) 84 85 log.Warningf("[this message should be sent to buf]") 86 entry, err := s.buf.ReadString('\n') 87 c.Assert(err, IsNil) 88 c.Assert(entry, Matches, logPattern) 89 90 log.Warnf("this message comes from logrus") 91 entry, err = s.buf.ReadString('\n') 92 c.Assert(err, IsNil) 93 c.Assert(entry, Matches, logPattern) 94 c.Assert(strings.Contains(entry, "log_test.go"), IsTrue) 95 } 96 97 func (s *testLogSuite) TestSlowQueryLogger(c *C) { 98 fileName := "slow_query" 99 os.Remove(fileName) 100 conf := NewLogConfig("info", DefaultLogFormat, fileName, NewFileLogConfig(DefaultLogMaxSize), false) 101 c.Assert(conf.File.MaxSize, Equals, DefaultLogMaxSize) 102 err := InitLogger(conf) 103 c.Assert(err, IsNil) 104 defer os.Remove(fileName) 105 106 SlowQueryLogger.Debug("debug message") 107 SlowQueryLogger.Info("info message") 108 SlowQueryLogger.Warn("warn message") 109 SlowQueryLogger.Error("error message") 110 c.Assert(s.buf.Len(), Equals, 0) 111 112 f, err := os.Open(fileName) 113 c.Assert(err, IsNil) 114 defer f.Close() 115 116 r := bufio.NewReader(f) 117 for { 118 var str string 119 str, err = r.ReadString('\n') 120 if err != nil { 121 break 122 } 123 if strings.HasPrefix(str, "# ") { 124 c.Assert(str, Matches, `# Time: .*?\n`) 125 } else { 126 c.Assert(str, Matches, `.*? message\n`) 127 } 128 } 129 c.Assert(err, Equals, io.EOF) 130 } 131 132 func (s *testLogSuite) TestLoggerKeepOrder(c *C) { 133 conf := NewLogConfig("warn", DefaultLogFormat, "", EmptyFileLogConfig, true) 134 c.Assert(InitLogger(conf), IsNil) 135 logger := log.StandardLogger() 136 ft, ok := logger.Formatter.(*textFormatter) 137 c.Assert(ok, IsTrue) 138 ft.EnableEntryOrder = true 139 logger.Out = s.buf 140 logEntry := log.NewEntry(logger) 141 logEntry.Data = log.Fields{ 142 "connectionId": 1, 143 "costTime": "1", 144 "database": "test", 145 "allegrosql": "select 1", 146 "txnStartTS": 1, 147 } 148 149 _, _, line, _ := runtime.Caller(0) 150 logEntry.WithField("type", "slow-query").WithField("succ", true).Warnf("slow-query") 151 expectMsg := fmt.Sprintf("log_test.go:%v: [warning] slow-query connectionId=1 costTime=1 database=test allegrosql=select 1 succ=true txnStartTS=1 type=slow-query\n", line+1) 152 c.Assert(s.buf.String(), Equals, expectMsg) 153 154 s.buf.Reset() 155 logEntry.Data = log.Fields{ 156 "a": "a", 157 "d": "d", 158 "e": "e", 159 "b": "b", 160 "f": "f", 161 "c": "c", 162 } 163 164 _, _, line, _ = runtime.Caller(0) 165 logEntry.Warnf("slow-query") 166 expectMsg = fmt.Sprintf("log_test.go:%v: [warning] slow-query a=a b=b c=c d=d e=e f=f\n", line+1) 167 c.Assert(s.buf.String(), Equals, expectMsg) 168 } 169 170 func (s *testLogSuite) TestSlowQueryZapLogger(c *C) { 171 if runtime.GOOS == "windows" { 172 // Skip this test on windows for two reasons: 173 // 1. The pattern match fails somehow. It seems windows treat \n as slash and character n. 174 // 2. Remove file doesn't work as long as the log instance hold the file. 175 c.Skip("skip on windows") 176 } 177 178 fileName := "slow_query" 179 conf := NewLogConfig("info", DefaultLogFormat, fileName, EmptyFileLogConfig, false) 180 err := InitZapLogger(conf) 181 c.Assert(err, IsNil) 182 defer os.Remove(fileName) 183 184 SlowQueryZapLogger.Debug("debug message", zap.String("str key", "val")) 185 SlowQueryZapLogger.Info("info message", zap.String("str key", "val")) 186 SlowQueryZapLogger.Warn("warn", zap.Int("int key", 123)) 187 SlowQueryZapLogger.Error("error message", zap.Bool("bool key", true)) 188 189 f, err := os.Open(fileName) 190 c.Assert(err, IsNil) 191 defer f.Close() 192 193 r := bufio.NewReader(f) 194 for { 195 var str string 196 str, err = r.ReadString('\n') 197 if err != nil { 198 break 199 } 200 c.Assert(str, Matches, zapLogPattern) 201 } 202 c.Assert(err, Equals, io.EOF) 203 204 } 205 206 func (s *testLogSuite) TestZapLoggerWithKeys(c *C) { 207 if runtime.GOOS == "windows" { 208 // Skip this test on windows for two reason: 209 // 1. The pattern match fails somehow. It seems windows treat \n as slash and character n. 210 // 2. Remove file doesn't work as long as the log instance hold the file. 211 c.Skip("skip on windows") 212 } 213 214 fileCfg := FileLogConfig{zaplog.FileLogConfig{Filename: "zap_log", MaxSize: 4096}} 215 conf := NewLogConfig("info", DefaultLogFormat, "", fileCfg, false) 216 err := InitZapLogger(conf) 217 c.Assert(err, IsNil) 218 connID := uint32(123) 219 ctx := WithConnID(context.Background(), connID) 220 s.testZapLogger(ctx, c, fileCfg.Filename, zapLogWithConnIDPattern) 221 os.Remove(fileCfg.Filename) 222 223 err = InitZapLogger(conf) 224 c.Assert(err, IsNil) 225 key := "ctxKey" 226 val := "ctxValue" 227 ctx1 := WithKeyValue(context.Background(), key, val) 228 s.testZapLogger(ctx1, c, fileCfg.Filename, zapLogWithKeyValPattern) 229 os.Remove(fileCfg.Filename) 230 } 231 232 func (s *testLogSuite) testZapLogger(ctx context.Context, c *C, fileName, pattern string) { 233 Logger(ctx).Debug("debug msg", zap.String("test with key", "true")) 234 Logger(ctx).Info("info msg", zap.String("test with key", "true")) 235 Logger(ctx).Warn("warn msg", zap.String("test with key", "true")) 236 Logger(ctx).Error("error msg", zap.String("test with key", "true")) 237 238 f, err := os.Open(fileName) 239 c.Assert(err, IsNil) 240 defer f.Close() 241 242 r := bufio.NewReader(f) 243 for { 244 var str string 245 str, err = r.ReadString('\n') 246 if err != nil { 247 break 248 } 249 c.Assert(str, Matches, pattern) 250 c.Assert(strings.Contains(str, "stack"), IsFalse) 251 c.Assert(strings.Contains(str, "errorVerbose"), IsFalse) 252 } 253 c.Assert(err, Equals, io.EOF) 254 } 255 256 func (s *testLogSuite) TestSetLevel(c *C) { 257 conf := NewLogConfig("info", DefaultLogFormat, "", EmptyFileLogConfig, false) 258 err := InitZapLogger(conf) 259 c.Assert(err, IsNil) 260 261 c.Assert(zaplog.GetLevel(), Equals, zap.InfoLevel) 262 err = SetLevel("warn") 263 c.Assert(err, IsNil) 264 c.Assert(zaplog.GetLevel(), Equals, zap.WarnLevel) 265 err = SetLevel("Error") 266 c.Assert(err, IsNil) 267 c.Assert(zaplog.GetLevel(), Equals, zap.ErrorLevel) 268 err = SetLevel("DEBUG") 269 c.Assert(err, IsNil) 270 c.Assert(zaplog.GetLevel(), Equals, zap.DebugLevel) 271 }