1package level_test 2 3import ( 4 "bytes" 5 "errors" 6 "io" 7 "strings" 8 "testing" 9 10 "github.com/go-kit/kit/log" 11 "github.com/go-kit/kit/log/level" 12) 13 14func TestVariousLevels(t *testing.T) { 15 testCases := []struct { 16 name string 17 allowed level.Option 18 want string 19 }{ 20 { 21 "AllowAll", 22 level.AllowAll(), 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 "AllowDebug", 32 level.AllowDebug(), 33 strings.Join([]string{ 34 `{"level":"debug","this is":"debug log"}`, 35 `{"level":"info","this is":"info log"}`, 36 `{"level":"warn","this is":"warn log"}`, 37 `{"level":"error","this is":"error log"}`, 38 }, "\n"), 39 }, 40 { 41 "AllowInfo", 42 level.AllowInfo(), 43 strings.Join([]string{ 44 `{"level":"info","this is":"info log"}`, 45 `{"level":"warn","this is":"warn log"}`, 46 `{"level":"error","this is":"error log"}`, 47 }, "\n"), 48 }, 49 { 50 "AllowWarn", 51 level.AllowWarn(), 52 strings.Join([]string{ 53 `{"level":"warn","this is":"warn log"}`, 54 `{"level":"error","this is":"error log"}`, 55 }, "\n"), 56 }, 57 { 58 "AllowError", 59 level.AllowError(), 60 strings.Join([]string{ 61 `{"level":"error","this is":"error log"}`, 62 }, "\n"), 63 }, 64 { 65 "AllowNone", 66 level.AllowNone(), 67 ``, 68 }, 69 } 70 71 for _, tc := range testCases { 72 t.Run(tc.name, func(t *testing.T) { 73 var buf bytes.Buffer 74 logger := level.NewFilter(log.NewJSONLogger(&buf), tc.allowed) 75 76 level.Debug(logger).Log("this is", "debug log") 77 level.Info(logger).Log("this is", "info log") 78 level.Warn(logger).Log("this is", "warn log") 79 level.Error(logger).Log("this is", "error log") 80 81 if want, have := tc.want, strings.TrimSpace(buf.String()); want != have { 82 t.Errorf("\nwant:\n%s\nhave:\n%s", want, have) 83 } 84 }) 85 } 86} 87 88func TestErrNotAllowed(t *testing.T) { 89 myError := errors.New("squelched!") 90 opts := []level.Option{ 91 level.AllowWarn(), 92 level.ErrNotAllowed(myError), 93 } 94 logger := level.NewFilter(log.NewNopLogger(), opts...) 95 96 if want, have := myError, level.Info(logger).Log("foo", "bar"); want != have { 97 t.Errorf("want %#+v, have %#+v", want, have) 98 } 99 100 if want, have := error(nil), level.Warn(logger).Log("foo", "bar"); want != have { 101 t.Errorf("want %#+v, have %#+v", want, have) 102 } 103} 104 105func TestErrNoLevel(t *testing.T) { 106 myError := errors.New("no level specified") 107 108 var buf bytes.Buffer 109 opts := []level.Option{ 110 level.SquelchNoLevel(true), 111 level.ErrNoLevel(myError), 112 } 113 logger := level.NewFilter(log.NewJSONLogger(&buf), opts...) 114 115 if want, have := myError, logger.Log("foo", "bar"); want != have { 116 t.Errorf("want %v, have %v", want, have) 117 } 118 if want, have := ``, strings.TrimSpace(buf.String()); want != have { 119 t.Errorf("\nwant '%s'\nhave '%s'", want, have) 120 } 121} 122 123func TestAllowNoLevel(t *testing.T) { 124 var buf bytes.Buffer 125 opts := []level.Option{ 126 level.SquelchNoLevel(false), 127 level.ErrNoLevel(errors.New("I should never be returned!")), 128 } 129 logger := level.NewFilter(log.NewJSONLogger(&buf), opts...) 130 131 if want, have := error(nil), logger.Log("foo", "bar"); want != have { 132 t.Errorf("want %v, have %v", want, have) 133 } 134 if want, have := `{"foo":"bar"}`, strings.TrimSpace(buf.String()); want != have { 135 t.Errorf("\nwant '%s'\nhave '%s'", want, have) 136 } 137} 138 139func TestLevelContext(t *testing.T) { 140 var buf bytes.Buffer 141 142 // Wrapping the level logger with a context allows users to use 143 // log.DefaultCaller as per normal. 144 var logger log.Logger 145 logger = log.NewLogfmtLogger(&buf) 146 logger = level.NewFilter(logger, level.AllowAll()) 147 logger = log.With(logger, "caller", log.DefaultCaller) 148 149 level.Info(logger).Log("foo", "bar") 150 if want, have := `level=info caller=level_test.go:149 foo=bar`, strings.TrimSpace(buf.String()); want != have { 151 t.Errorf("\nwant '%s'\nhave '%s'", want, have) 152 } 153} 154 155func TestContextLevel(t *testing.T) { 156 var buf bytes.Buffer 157 158 // Wrapping a context with the level logger still works, but requires users 159 // to specify a higher callstack depth value. 160 var logger log.Logger 161 logger = log.NewLogfmtLogger(&buf) 162 logger = log.With(logger, "caller", log.Caller(5)) 163 logger = level.NewFilter(logger, level.AllowAll()) 164 165 level.Info(logger).Log("foo", "bar") 166 if want, have := `caller=level_test.go:165 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have { 167 t.Errorf("\nwant '%s'\nhave '%s'", want, have) 168 } 169} 170 171func TestLevelFormatting(t *testing.T) { 172 testCases := []struct { 173 name string 174 format func(io.Writer) log.Logger 175 output string 176 }{ 177 { 178 name: "logfmt", 179 format: log.NewLogfmtLogger, 180 output: `level=info foo=bar`, 181 }, 182 { 183 name: "JSON", 184 format: log.NewJSONLogger, 185 output: `{"foo":"bar","level":"info"}`, 186 }, 187 } 188 189 for _, tc := range testCases { 190 t.Run(tc.name, func(t *testing.T) { 191 var buf bytes.Buffer 192 193 logger := tc.format(&buf) 194 level.Info(logger).Log("foo", "bar") 195 if want, have := tc.output, strings.TrimSpace(buf.String()); want != have { 196 t.Errorf("\nwant: '%s'\nhave '%s'", want, have) 197 } 198 }) 199 } 200} 201 202func TestInjector(t *testing.T) { 203 var ( 204 output []interface{} 205 logger log.Logger 206 ) 207 208 logger = log.LoggerFunc(func(keyvals ...interface{}) error { 209 output = keyvals 210 return nil 211 }) 212 logger = level.NewInjector(logger, level.InfoValue()) 213 214 logger.Log("foo", "bar") 215 if got, want := len(output), 4; got != want { 216 t.Errorf("missing level not injected: got len==%d, want len==%d", got, want) 217 } 218 if got, want := output[0], level.Key(); got != want { 219 t.Errorf("wrong level key: got %#v, want %#v", got, want) 220 } 221 if got, want := output[1], level.InfoValue(); got != want { 222 t.Errorf("wrong level value: got %#v, want %#v", got, want) 223 } 224 225 level.Error(logger).Log("foo", "bar") 226 if got, want := len(output), 4; got != want { 227 t.Errorf("leveled record modified: got len==%d, want len==%d", got, want) 228 } 229 if got, want := output[0], level.Key(); got != want { 230 t.Errorf("wrong level key: got %#v, want %#v", got, want) 231 } 232 if got, want := output[1], level.ErrorValue(); got != want { 233 t.Errorf("wrong level value: got %#v, want %#v", got, want) 234 } 235} 236