github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/goutils/logger/logger_test.go (about) 1 /* 2 * Copyright (c) 2020-present unTill Pro, Ltd. 3 * @author Maxim Geraskin 4 * 5 * This source code is licensed under the MIT license found in the 6 * LICENSE file in the root directory of this source tree. 7 */ 8 9 package logger_test 10 11 import ( 12 "bytes" 13 "io" 14 "os" 15 "strconv" 16 "strings" 17 "sync" 18 "testing" 19 20 "github.com/stretchr/testify/require" 21 "github.com/voedger/voedger/pkg/goutils/logger" 22 "github.com/voedger/voedger/pkg/goutils/testingu" 23 ) 24 25 func Test_BasicUsage(t *testing.T) { 26 27 // "Hello world" 28 { 29 logger.Error("Error", "arg1", "arg2") 30 logger.Warning("My warning") 31 logger.Info("My info") 32 33 // IsVerbose() is used to avoid unnecessary calculations 34 if logger.IsVerbose() { 35 logger.Verbose("!!! You should NOT see this verbose message since default level is INFO") 36 } 37 38 // IsTrace() is used to avoid unnecessary calculations 39 if logger.IsTrace() { 40 logger.Trace("!!! You should NOT see this trace message since default level is INFO") 41 } 42 } 43 44 // Changing LogLevel 45 { 46 logger.SetLogLevel(logger.LogLevelTrace) 47 if logger.IsTrace() { 48 logger.Trace("Now you should see my Trace") 49 } 50 if logger.IsVerbose() { 51 logger.Verbose("Now you should see my Verbose") 52 } 53 logger.SetLogLevel(logger.LogLevelError) 54 logger.Trace("!!! You should NOT see my Trace") 55 logger.Warning("!!! You should NOT see my warning") 56 logger.SetLogLevel(logger.LogLevelInfo) 57 logger.Warning("You should see my warning") 58 logger.Warning("You should see my info") 59 } 60 61 // Let see how it looks when using from methods 62 { 63 m := mystruct{} 64 m.iWantToLog() 65 } 66 } 67 68 func loggerHelperWithSkipStackFrames(skipStackFrames int, msg string) error { 69 logger.Log(skipStackFrames, logger.LogLevelTrace, "myStunningPrefix:", msg) 70 return nil 71 } 72 73 func Test_BasicUsage_SkipStackFrames(t *testing.T) { 74 75 logger.SetLogLevel(logger.LogLevelTrace) 76 77 // [logger_test.loggerHelperWithSkipStackFrames:...]: myStunningPrefix: hello 78 _ = loggerHelperWithSkipStackFrames(0, "hello") 79 80 // logger_test.Test_SkipStackFrames:...]: myStunningPrefix: hello 81 _ = loggerHelperWithSkipStackFrames(1, "hello") 82 } 83 84 func Test_BasicUsage_CustomPrintLine(t *testing.T) { 85 86 require := require.New(t) 87 88 // Define myPrintLine 89 myPrintLine := func(level logger.TLogLevel, line string) { 90 line += "myPrintLine" 91 logger.DefaultPrintLine(level, line) 92 } 93 94 // Use myPrintLine as logger.PrintLine 95 96 logger.PrintLine = myPrintLine 97 defer func() { 98 logger.PrintLine = logger.DefaultPrintLine 99 }() 100 101 { 102 logger.SetLogLevel(logger.LogLevelTrace) 103 strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error { 104 logger.Trace("hello") 105 return nil 106 }) 107 require.NoError(err) 108 require.Equal("", strStderr) 109 require.Contains(strStdout, "myPrintLine") 110 } 111 112 } 113 114 func Test_SkipStackFrames(t *testing.T) { 115 116 require := require.New(t) 117 logger.SetLogLevel(logger.LogLevelTrace) 118 119 const funcNamePattern = "loggerHelperWithSkipStackFrames" 120 121 { 122 // [logger_test.loggerHelperSkip0StackFrames:69]: myStunningPrefix: hello 123 strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error { 124 return loggerHelperWithSkipStackFrames(0, "hello") 125 }) 126 require.NoError(err) 127 require.Equal("", strStderr) 128 require.Contains(strStdout, funcNamePattern) 129 } 130 131 { 132 // logger_test.Test_SkipStackFrames:80]: myStunningPrefix: hello 133 strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error { 134 return loggerHelperWithSkipStackFrames(1, "hello") 135 }) 136 require.NoError(err) 137 require.Equal("", strStderr) 138 require.NotContains(strStdout, funcNamePattern) 139 } 140 141 } 142 143 func Test_StdoutStderr_LogLevel(t *testing.T) { 144 145 require := require.New(t) 146 147 // LogLevelError 148 { 149 logger.SetLogLevel(logger.LogLevelError) 150 strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error { 151 logger.Error("Error", "arg1", "arg2") 152 logger.Warning("My warning") 153 return nil 154 }) 155 require.NoError(err) 156 require.Contains(strStderr, "Error arg1 arg2") 157 require.Equal("", strStdout) 158 } 159 160 // LogLevelWarning 161 { 162 logger.SetLogLevel(logger.LogLevelWarning) 163 strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error { 164 logger.Error("Error", "arg1", "arg2") 165 logger.Warning("My warning") 166 return nil 167 }) 168 require.NoError(err) 169 require.Contains(strStderr, "Error arg1 arg2") 170 require.Contains(strStdout, "My warning") 171 } 172 173 } 174 175 func Test_CheckSetLevels(t *testing.T) { 176 177 require := require.New(t) 178 179 logger.SetLogLevel(logger.LogLevelNone) 180 require.False(logger.IsError()) 181 require.False(logger.IsWarning()) 182 require.False(logger.IsInfo()) 183 require.False(logger.IsVerbose()) 184 require.False(logger.IsTrace()) 185 186 logger.SetLogLevel(logger.LogLevelError) 187 require.True(logger.IsError()) 188 require.False(logger.IsWarning()) 189 require.False(logger.IsInfo()) 190 require.False(logger.IsVerbose()) 191 require.False(logger.IsTrace()) 192 193 logger.SetLogLevel(logger.LogLevelWarning) 194 require.True(logger.IsError()) 195 require.True(logger.IsWarning()) 196 require.False(logger.IsInfo()) 197 require.False(logger.IsVerbose()) 198 require.False(logger.IsTrace()) 199 200 logger.SetLogLevel(logger.LogLevelInfo) 201 require.True(logger.IsError()) 202 require.True(logger.IsWarning()) 203 require.True(logger.IsInfo()) 204 require.False(logger.IsVerbose()) 205 require.False(logger.IsTrace()) 206 207 logger.SetLogLevel(logger.LogLevelVerbose) 208 require.True(logger.IsError()) 209 require.True(logger.IsWarning()) 210 require.True(logger.IsInfo()) 211 require.True(logger.IsVerbose()) 212 require.False(logger.IsTrace()) 213 214 logger.SetLogLevel(logger.LogLevelTrace) 215 require.True(logger.IsError()) 216 require.True(logger.IsWarning()) 217 require.True(logger.IsInfo()) 218 require.True(logger.IsVerbose()) 219 require.True(logger.IsTrace()) 220 221 } 222 223 type mystruct struct { 224 } 225 226 func (m *mystruct) iWantToLog() { 227 logger.Error("OOPS") 228 } 229 230 func TestMultithread(t *testing.T) { 231 require := require.New(t) 232 r, w, err := os.Pipe() 233 require.NoError(err) 234 oldStdout := os.Stdout 235 defer func() { os.Stdout = oldStdout }() 236 os.Stdout = w 237 wg := sync.WaitGroup{} 238 wg.Add(1000) 239 240 toLog := []string{} 241 for i := 0; i < 100; i++ { 242 toLog = append(toLog, strings.Repeat(strconv.Itoa(i), 10)) 243 } 244 245 for i := 0; i < 1000; i++ { 246 go func() { 247 for i := 0; i < 100; i++ { 248 logger.Info(toLog[i]) 249 } 250 wg.Done() 251 }() 252 } 253 254 stdout := "" 255 wait := make(chan struct{}) 256 go func() { 257 buf := bytes.NewBuffer(nil) 258 _, err := io.Copy(buf, r) 259 require.NoError(err) 260 stdout = buf.String() 261 close(wait) 262 }() 263 wg.Wait() 264 w.Close() 265 <-wait 266 267 logged := strings.Split(stdout, "\n") 268 outer: 269 for _, loggedActual := range logged { 270 if len(loggedActual) == 0 { 271 continue 272 } 273 for _, loggedExpected := range toLog { 274 if strings.Contains(loggedActual, loggedExpected) { 275 continue outer 276 } 277 } 278 t.Fatal(loggedActual) 279 } 280 }