11 "github.com/stretchr/testify/assert"
14 func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
15 var buffer bytes.Buffer
20 logger.Formatter = new(JSONFormatter)
24 err := json.Unmarshal(buffer.Bytes(), &fields)
30 func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
31 var buffer bytes.Buffer
35 logger.Formatter = &TextFormatter{
41 fields := make(map[string]string)
42 for _, kv := range strings.Split(buffer.String(), " ") {
43 if !strings.Contains(kv, "=") {
46 kvArr := strings.Split(kv, "=")
47 key := strings.TrimSpace(kvArr[0])
49 if kvArr[1][0] == '"' {
51 val, err = strconv.Unquote(val)
52 assert.NoError(t, err)
59 func TestPrint(t *testing.T) {
60 LogAndAssertJSON(t, func(log *Logger) {
62 }, func(fields Fields) {
63 assert.Equal(t, fields["msg"], "test")
64 assert.Equal(t, fields["level"], "info")
68 func TestInfo(t *testing.T) {
69 LogAndAssertJSON(t, func(log *Logger) {
71 }, func(fields Fields) {
72 assert.Equal(t, fields["msg"], "test")
73 assert.Equal(t, fields["level"], "info")
77 func TestWarn(t *testing.T) {
78 LogAndAssertJSON(t, func(log *Logger) {
80 }, func(fields Fields) {
81 assert.Equal(t, fields["msg"], "test")
82 assert.Equal(t, fields["level"], "warning")
86 func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
87 LogAndAssertJSON(t, func(log *Logger) {
88 log.Infoln("test", "test")
89 }, func(fields Fields) {
90 assert.Equal(t, fields["msg"], "test test")
94 func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
95 LogAndAssertJSON(t, func(log *Logger) {
96 log.Infoln("test", 10)
97 }, func(fields Fields) {
98 assert.Equal(t, fields["msg"], "test 10")
102 func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
103 LogAndAssertJSON(t, func(log *Logger) {
105 }, func(fields Fields) {
106 assert.Equal(t, fields["msg"], "10 10")
110 func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
111 LogAndAssertJSON(t, func(log *Logger) {
113 }, func(fields Fields) {
114 assert.Equal(t, fields["msg"], "10 10")
118 func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
119 LogAndAssertJSON(t, func(log *Logger) {
121 }, func(fields Fields) {
122 assert.Equal(t, fields["msg"], "test10")
126 func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
127 LogAndAssertJSON(t, func(log *Logger) {
128 log.Info("test", "test")
129 }, func(fields Fields) {
130 assert.Equal(t, fields["msg"], "testtest")
134 func TestWithFieldsShouldAllowAssignments(t *testing.T) {
135 var buffer bytes.Buffer
140 logger.Formatter = new(JSONFormatter)
142 localLog := logger.WithFields(Fields{
146 localLog.WithField("key2", "value2").Info("test")
147 err := json.Unmarshal(buffer.Bytes(), &fields)
150 assert.Equal(t, "value2", fields["key2"])
151 assert.Equal(t, "value1", fields["key1"])
153 buffer = bytes.Buffer{}
155 localLog.Info("test")
156 err = json.Unmarshal(buffer.Bytes(), &fields)
159 _, ok := fields["key2"]
160 assert.Equal(t, false, ok)
161 assert.Equal(t, "value1", fields["key1"])
164 func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
165 LogAndAssertJSON(t, func(log *Logger) {
166 log.WithField("msg", "hello").Info("test")
167 }, func(fields Fields) {
168 assert.Equal(t, fields["msg"], "test")
172 func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
173 LogAndAssertJSON(t, func(log *Logger) {
174 log.WithField("msg", "hello").Info("test")
175 }, func(fields Fields) {
176 assert.Equal(t, fields["msg"], "test")
177 assert.Equal(t, fields["fields.msg"], "hello")
181 func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
182 LogAndAssertJSON(t, func(log *Logger) {
183 log.WithField("time", "hello").Info("test")
184 }, func(fields Fields) {
185 assert.Equal(t, fields["fields.time"], "hello")
189 func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
190 LogAndAssertJSON(t, func(log *Logger) {
191 log.WithField("level", 1).Info("test")
192 }, func(fields Fields) {
193 assert.Equal(t, fields["level"], "info")
194 assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only
198 func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
199 LogAndAssertText(t, func(log *Logger) {
200 ll := log.WithField("herp", "derp")
203 }, func(fields map[string]string) {
204 for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
205 if _, ok := fields[fieldName]; ok {
206 t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
212 func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
214 var buffer bytes.Buffer
219 logger.Formatter = new(JSONFormatter)
221 llog := logger.WithField("context", "eating raw fish")
223 llog.Info("looks delicious")
225 err := json.Unmarshal(buffer.Bytes(), &fields)
226 assert.NoError(t, err, "should have decoded first message")
227 assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
228 assert.Equal(t, fields["msg"], "looks delicious")
229 assert.Equal(t, fields["context"], "eating raw fish")
233 llog.Warn("omg it is!")
235 err = json.Unmarshal(buffer.Bytes(), &fields)
236 assert.NoError(t, err, "should have decoded second message")
237 assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
238 assert.Equal(t, fields["msg"], "omg it is!")
239 assert.Equal(t, fields["context"], "eating raw fish")
240 assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
244 func TestConvertLevelToString(t *testing.T) {
245 assert.Equal(t, "debug", DebugLevel.String())
246 assert.Equal(t, "info", InfoLevel.String())
247 assert.Equal(t, "warning", WarnLevel.String())
248 assert.Equal(t, "error", ErrorLevel.String())
249 assert.Equal(t, "fatal", FatalLevel.String())
250 assert.Equal(t, "panic", PanicLevel.String())
253 func TestParseLevel(t *testing.T) {
254 l, err := ParseLevel("panic")
256 assert.Equal(t, PanicLevel, l)
258 l, err = ParseLevel("PANIC")
260 assert.Equal(t, PanicLevel, l)
262 l, err = ParseLevel("fatal")
264 assert.Equal(t, FatalLevel, l)
266 l, err = ParseLevel("FATAL")
268 assert.Equal(t, FatalLevel, l)
270 l, err = ParseLevel("error")
272 assert.Equal(t, ErrorLevel, l)
274 l, err = ParseLevel("ERROR")
276 assert.Equal(t, ErrorLevel, l)
278 l, err = ParseLevel("warn")
280 assert.Equal(t, WarnLevel, l)
282 l, err = ParseLevel("WARN")
284 assert.Equal(t, WarnLevel, l)
286 l, err = ParseLevel("warning")
288 assert.Equal(t, WarnLevel, l)
290 l, err = ParseLevel("WARNING")
292 assert.Equal(t, WarnLevel, l)
294 l, err = ParseLevel("info")
296 assert.Equal(t, InfoLevel, l)
298 l, err = ParseLevel("INFO")
300 assert.Equal(t, InfoLevel, l)
302 l, err = ParseLevel("debug")
304 assert.Equal(t, DebugLevel, l)
306 l, err = ParseLevel("DEBUG")
308 assert.Equal(t, DebugLevel, l)
310 l, err = ParseLevel("invalid")
311 assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
314 func TestGetSetLevelRace(t *testing.T) {
315 wg := sync.WaitGroup{}
316 for i := 0; i < 100; i++ {
331 func TestLoggingRace(t *testing.T) {
334 var wg sync.WaitGroup
337 for i := 0; i < 100; i++ {
347 func TestLogrusInterface(t *testing.T) {
348 var buffer bytes.Buffer
349 fn := func(l FieldLogger) {
350 b := l.WithField("key", "value")
359 e := logger.WithField("another", "value")
363 // Implements io.Writer using channels for synchronization, so we can wait on
364 // the Entry.Writer goroutine to write in a non-racey way. This does assume that
365 // there is a single call to Logger.Out for each message.
366 type channelWriter chan []byte
368 func (cw channelWriter) Write(p []byte) (int, error) {
373 func TestEntryWriter(t *testing.T) {
374 cw := channelWriter(make(chan []byte, 1))
377 log.Formatter = new(JSONFormatter)
378 log.WithField("foo", "bar").WriterLevel(WarnLevel).Write([]byte("hello\n"))
382 err := json.Unmarshal(bs, &fields)
384 assert.Equal(t, fields["foo"], "bar")
385 assert.Equal(t, fields["level"], "warning")