github.com/go-kit/log@v0.2.1/level/level_test.go (about) 1 package level_test 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "strings" 8 "testing" 9 10 "github.com/go-kit/log" 11 "github.com/go-kit/log/level" 12 ) 13 14 func TestVariousLevels(t *testing.T) { 15 testCases := []struct { 16 name string 17 allowed level.Option 18 want string 19 }{ 20 { 21 "Allow(DebugValue)", 22 level.Allow(level.DebugValue()), 23 strings.Join([]string{ 24 `{"level":"debug","this is":"debug log"}`, 25 `{"level":"info","this is":"info log"}`, 26 `{"level":"warn","this is":"warn log"}`, 27 `{"level":"error","this is":"error log"}`, 28 }, "\n"), 29 }, 30 { 31 "Allow(InfoValue)", 32 level.Allow(level.InfoValue()), 33 strings.Join([]string{ 34 `{"level":"info","this is":"info log"}`, 35 `{"level":"warn","this is":"warn log"}`, 36 `{"level":"error","this is":"error log"}`, 37 }, "\n"), 38 }, 39 { 40 "Allow(WarnValue)", 41 level.Allow(level.WarnValue()), 42 strings.Join([]string{ 43 `{"level":"warn","this is":"warn log"}`, 44 `{"level":"error","this is":"error log"}`, 45 }, "\n"), 46 }, 47 { 48 "Allow(ErrorValue)", 49 level.Allow(level.ErrorValue()), 50 strings.Join([]string{ 51 `{"level":"error","this is":"error log"}`, 52 }, "\n"), 53 }, 54 { 55 "Allow(nil)", 56 level.Allow(nil), 57 strings.Join([]string{}, "\n"), 58 }, 59 { 60 "AllowAll", 61 level.AllowAll(), 62 strings.Join([]string{ 63 `{"level":"debug","this is":"debug log"}`, 64 `{"level":"info","this is":"info log"}`, 65 `{"level":"warn","this is":"warn log"}`, 66 `{"level":"error","this is":"error log"}`, 67 }, "\n"), 68 }, 69 { 70 "AllowDebug", 71 level.AllowDebug(), 72 strings.Join([]string{ 73 `{"level":"debug","this is":"debug log"}`, 74 `{"level":"info","this is":"info log"}`, 75 `{"level":"warn","this is":"warn log"}`, 76 `{"level":"error","this is":"error log"}`, 77 }, "\n"), 78 }, 79 { 80 "AllowInfo", 81 level.AllowInfo(), 82 strings.Join([]string{ 83 `{"level":"info","this is":"info log"}`, 84 `{"level":"warn","this is":"warn log"}`, 85 `{"level":"error","this is":"error log"}`, 86 }, "\n"), 87 }, 88 { 89 "AllowWarn", 90 level.AllowWarn(), 91 strings.Join([]string{ 92 `{"level":"warn","this is":"warn log"}`, 93 `{"level":"error","this is":"error log"}`, 94 }, "\n"), 95 }, 96 { 97 "AllowError", 98 level.AllowError(), 99 strings.Join([]string{ 100 `{"level":"error","this is":"error log"}`, 101 }, "\n"), 102 }, 103 { 104 "AllowNone", 105 level.AllowNone(), 106 ``, 107 }, 108 } 109 110 for _, tc := range testCases { 111 t.Run(tc.name, func(t *testing.T) { 112 var buf bytes.Buffer 113 logger := level.NewFilter(log.NewJSONLogger(&buf), tc.allowed) 114 115 level.Debug(logger).Log("this is", "debug log") 116 level.Info(logger).Log("this is", "info log") 117 level.Warn(logger).Log("this is", "warn log") 118 level.Error(logger).Log("this is", "error log") 119 120 if want, have := tc.want, strings.TrimSpace(buf.String()); want != have { 121 t.Errorf("\nwant:\n%s\nhave:\n%s", want, have) 122 } 123 }) 124 } 125 } 126 127 func TestErrNotAllowed(t *testing.T) { 128 myError := errors.New("squelched!") 129 opts := []level.Option{ 130 level.AllowWarn(), 131 level.ErrNotAllowed(myError), 132 } 133 logger := level.NewFilter(log.NewNopLogger(), opts...) 134 135 if want, have := myError, level.Info(logger).Log("foo", "bar"); want != have { 136 t.Errorf("want %#+v, have %#+v", want, have) 137 } 138 139 if want, have := error(nil), level.Warn(logger).Log("foo", "bar"); want != have { 140 t.Errorf("want %#+v, have %#+v", want, have) 141 } 142 } 143 144 func TestErrNoLevel(t *testing.T) { 145 myError := errors.New("no level specified") 146 147 var buf bytes.Buffer 148 opts := []level.Option{ 149 level.SquelchNoLevel(true), 150 level.ErrNoLevel(myError), 151 } 152 logger := level.NewFilter(log.NewJSONLogger(&buf), opts...) 153 154 if want, have := myError, logger.Log("foo", "bar"); want != have { 155 t.Errorf("want %v, have %v", want, have) 156 } 157 if want, have := ``, strings.TrimSpace(buf.String()); want != have { 158 t.Errorf("\nwant '%s'\nhave '%s'", want, have) 159 } 160 } 161 162 func TestAllowNoLevel(t *testing.T) { 163 var buf bytes.Buffer 164 opts := []level.Option{ 165 level.SquelchNoLevel(false), 166 level.ErrNoLevel(errors.New("I should never be returned!")), 167 } 168 logger := level.NewFilter(log.NewJSONLogger(&buf), opts...) 169 170 if want, have := error(nil), logger.Log("foo", "bar"); want != have { 171 t.Errorf("want %v, have %v", want, have) 172 } 173 if want, have := `{"foo":"bar"}`, strings.TrimSpace(buf.String()); want != have { 174 t.Errorf("\nwant '%s'\nhave '%s'", want, have) 175 } 176 } 177 178 func TestLevelContext(t *testing.T) { 179 var buf bytes.Buffer 180 181 // Wrapping the level logger with a context allows users to use 182 // log.DefaultCaller as per normal. 183 var logger log.Logger 184 logger = log.NewLogfmtLogger(&buf) 185 logger = level.NewFilter(logger, level.AllowAll()) 186 logger = log.With(logger, "caller", log.DefaultCaller) 187 188 level.Info(logger).Log("foo", "bar") 189 if want, have := `level=info caller=level_test.go:188 foo=bar`, strings.TrimSpace(buf.String()); want != have { 190 t.Errorf("\nwant '%s'\nhave '%s'", want, have) 191 } 192 } 193 194 func TestContextLevel(t *testing.T) { 195 var buf bytes.Buffer 196 197 // Wrapping a context with the level logger still works, but requires users 198 // to specify a higher callstack depth value. 199 var logger log.Logger 200 logger = log.NewLogfmtLogger(&buf) 201 logger = log.With(logger, "caller", log.Caller(5)) 202 logger = level.NewFilter(logger, level.AllowAll()) 203 204 level.Info(logger).Log("foo", "bar") 205 if want, have := `caller=level_test.go:204 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have { 206 t.Errorf("\nwant '%s'\nhave '%s'", want, have) 207 } 208 } 209 210 func TestLevelFormatting(t *testing.T) { 211 testCases := []struct { 212 name string 213 format func(io.Writer) log.Logger 214 output string 215 }{ 216 { 217 name: "logfmt", 218 format: log.NewLogfmtLogger, 219 output: `level=info foo=bar`, 220 }, 221 { 222 name: "JSON", 223 format: log.NewJSONLogger, 224 output: `{"foo":"bar","level":"info"}`, 225 }, 226 } 227 228 for _, tc := range testCases { 229 t.Run(tc.name, func(t *testing.T) { 230 var buf bytes.Buffer 231 232 logger := tc.format(&buf) 233 level.Info(logger).Log("foo", "bar") 234 if want, have := tc.output, strings.TrimSpace(buf.String()); want != have { 235 t.Errorf("\nwant: '%s'\nhave '%s'", want, have) 236 } 237 }) 238 } 239 } 240 241 func TestInjector(t *testing.T) { 242 var ( 243 output []interface{} 244 logger log.Logger 245 ) 246 247 logger = log.LoggerFunc(func(keyvals ...interface{}) error { 248 output = keyvals 249 return nil 250 }) 251 logger = level.NewInjector(logger, level.InfoValue()) 252 253 logger.Log("foo", "bar") 254 if got, want := len(output), 4; got != want { 255 t.Errorf("missing level not injected: got len==%d, want len==%d", got, want) 256 } 257 if got, want := output[0], level.Key(); got != want { 258 t.Errorf("wrong level key: got %#v, want %#v", got, want) 259 } 260 if got, want := output[1], level.InfoValue(); got != want { 261 t.Errorf("wrong level value: got %#v, want %#v", got, want) 262 } 263 264 level.Error(logger).Log("foo", "bar") 265 if got, want := len(output), 4; got != want { 266 t.Errorf("leveled record modified: got len==%d, want len==%d", got, want) 267 } 268 if got, want := output[0], level.Key(); got != want { 269 t.Errorf("wrong level key: got %#v, want %#v", got, want) 270 } 271 if got, want := output[1], level.ErrorValue(); got != want { 272 t.Errorf("wrong level value: got %#v, want %#v", got, want) 273 } 274 } 275 276 func TestParse(t *testing.T) { 277 testCases := []struct { 278 name string 279 level string 280 want level.Value 281 wantErr error 282 }{ 283 { 284 name: "Debug", 285 level: "debug", 286 want: level.DebugValue(), 287 wantErr: nil, 288 }, 289 { 290 name: "Info", 291 level: "info", 292 want: level.InfoValue(), 293 wantErr: nil, 294 }, 295 { 296 name: "Warn", 297 level: "warn", 298 want: level.WarnValue(), 299 wantErr: nil, 300 }, 301 { 302 name: "Error", 303 level: "error", 304 want: level.ErrorValue(), 305 wantErr: nil, 306 }, 307 { 308 name: "Case Insensitive", 309 level: "ErRoR", 310 want: level.ErrorValue(), 311 wantErr: nil, 312 }, 313 { 314 name: "Trimmed", 315 level: " Error ", 316 want: level.ErrorValue(), 317 wantErr: nil, 318 }, 319 { 320 name: "Invalid", 321 level: "invalid", 322 want: nil, 323 wantErr: level.ErrInvalidLevelString, 324 }, 325 } 326 327 for _, tc := range testCases { 328 t.Run(tc.name, func(t *testing.T) { 329 got, err := level.Parse(tc.level) 330 if err != tc.wantErr { 331 t.Errorf("got unexpected error %#v", err) 332 } 333 334 if got != tc.want { 335 t.Errorf("wrong value: got=%#v, want=%#v", got, tc.want) 336 } 337 }) 338 } 339 } 340 341 func TestParseDefault(t *testing.T) { 342 testCases := []struct { 343 name string 344 level string 345 want level.Value 346 }{ 347 { 348 name: "Debug", 349 level: "debug", 350 want: level.DebugValue(), 351 }, 352 { 353 name: "Info", 354 level: "info", 355 want: level.InfoValue(), 356 }, 357 { 358 name: "Warn", 359 level: "warn", 360 want: level.WarnValue(), 361 }, 362 { 363 name: "Error", 364 level: "error", 365 want: level.ErrorValue(), 366 }, 367 { 368 name: "Case Insensitive", 369 level: "ErRoR", 370 want: level.ErrorValue(), 371 }, 372 { 373 name: "Trimmed", 374 level: " Error ", 375 want: level.ErrorValue(), 376 }, 377 { 378 name: "Invalid", 379 level: "invalid", 380 want: level.InfoValue(), 381 }, 382 } 383 384 for _, tc := range testCases { 385 t.Run(tc.name, func(t *testing.T) { 386 got := level.ParseDefault(tc.level, level.InfoValue()) 387 388 if got != tc.want { 389 t.Errorf("wrong value: got=%#v, want=%#v", got, tc.want) 390 } 391 }) 392 } 393 }