1package logrus_test
2
3import (
4	"bytes"
5	"encoding/json"
6	"fmt"
7	"io/ioutil"
8	"os"
9	"path/filepath"
10	"runtime"
11	"sync"
12	"testing"
13	"time"
14
15	"github.com/stretchr/testify/assert"
16	"github.com/stretchr/testify/require"
17
18	. "github.com/sirupsen/logrus"
19	. "github.com/sirupsen/logrus/internal/testutils"
20)
21
22// TestReportCaller verifies that when ReportCaller is set, the 'func' field
23// is added, and when it is unset it is not set or modified
24// Verify that functions within the Logrus package aren't considered when
25// discovering the caller.
26func TestReportCallerWhenConfigured(t *testing.T) {
27	LogAndAssertJSON(t, func(log *Logger) {
28		log.ReportCaller = false
29		log.Print("testNoCaller")
30	}, func(fields Fields) {
31		assert.Equal(t, "testNoCaller", fields["msg"])
32		assert.Equal(t, "info", fields["level"])
33		assert.Equal(t, nil, fields["func"])
34	})
35
36	LogAndAssertJSON(t, func(log *Logger) {
37		log.ReportCaller = true
38		log.Print("testWithCaller")
39	}, func(fields Fields) {
40		assert.Equal(t, "testWithCaller", fields["msg"])
41		assert.Equal(t, "info", fields["level"])
42		assert.Equal(t,
43			"github.com/sirupsen/logrus_test.TestReportCallerWhenConfigured.func3", fields[FieldKeyFunc])
44	})
45
46	LogAndAssertJSON(t, func(log *Logger) {
47		log.ReportCaller = true
48		log.Formatter.(*JSONFormatter).CallerPrettyfier = func(f *runtime.Frame) (string, string) {
49			return "somekindoffunc", "thisisafilename"
50		}
51		log.Print("testWithCallerPrettyfier")
52	}, func(fields Fields) {
53		assert.Equal(t, "somekindoffunc", fields[FieldKeyFunc])
54		assert.Equal(t, "thisisafilename", fields[FieldKeyFile])
55	})
56
57	LogAndAssertText(t, func(log *Logger) {
58		log.ReportCaller = true
59		log.Formatter.(*TextFormatter).CallerPrettyfier = func(f *runtime.Frame) (string, string) {
60			return "somekindoffunc", "thisisafilename"
61		}
62		log.Print("testWithCallerPrettyfier")
63	}, func(fields map[string]string) {
64		assert.Equal(t, "somekindoffunc", fields[FieldKeyFunc])
65		assert.Equal(t, "thisisafilename", fields[FieldKeyFile])
66	})
67}
68
69func logSomething(t *testing.T, message string) Fields {
70	var buffer bytes.Buffer
71	var fields Fields
72
73	logger := New()
74	logger.Out = &buffer
75	logger.Formatter = new(JSONFormatter)
76	logger.ReportCaller = true
77
78	entry := logger.WithFields(Fields{
79		"foo": "bar",
80	})
81
82	entry.Info(message)
83
84	err := json.Unmarshal(buffer.Bytes(), &fields)
85	assert.Nil(t, err)
86
87	return fields
88}
89
90// TestReportCallerHelperDirect - verify reference when logging from a regular function
91func TestReportCallerHelperDirect(t *testing.T) {
92	fields := logSomething(t, "direct")
93
94	assert.Equal(t, "direct", fields["msg"])
95	assert.Equal(t, "info", fields["level"])
96	assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"])
97}
98
99// TestReportCallerHelperDirect - verify reference when logging from a function called via pointer
100func TestReportCallerHelperViaPointer(t *testing.T) {
101	fptr := logSomething
102	fields := fptr(t, "via pointer")
103
104	assert.Equal(t, "via pointer", fields["msg"])
105	assert.Equal(t, "info", fields["level"])
106	assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"])
107}
108
109func TestPrint(t *testing.T) {
110	LogAndAssertJSON(t, func(log *Logger) {
111		log.Print("test")
112	}, func(fields Fields) {
113		assert.Equal(t, "test", fields["msg"])
114		assert.Equal(t, "info", fields["level"])
115	})
116}
117
118func TestInfo(t *testing.T) {
119	LogAndAssertJSON(t, func(log *Logger) {
120		log.Info("test")
121	}, func(fields Fields) {
122		assert.Equal(t, "test", fields["msg"])
123		assert.Equal(t, "info", fields["level"])
124	})
125}
126
127func TestWarn(t *testing.T) {
128	LogAndAssertJSON(t, func(log *Logger) {
129		log.Warn("test")
130	}, func(fields Fields) {
131		assert.Equal(t, "test", fields["msg"])
132		assert.Equal(t, "warning", fields["level"])
133	})
134}
135
136func TestLog(t *testing.T) {
137	LogAndAssertJSON(t, func(log *Logger) {
138		log.Log(WarnLevel, "test")
139	}, func(fields Fields) {
140		assert.Equal(t, "test", fields["msg"])
141		assert.Equal(t, "warning", fields["level"])
142	})
143}
144
145func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
146	LogAndAssertJSON(t, func(log *Logger) {
147		log.Infoln("test", "test")
148	}, func(fields Fields) {
149		assert.Equal(t, "test test", fields["msg"])
150	})
151}
152
153func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
154	LogAndAssertJSON(t, func(log *Logger) {
155		log.Infoln("test", 10)
156	}, func(fields Fields) {
157		assert.Equal(t, "test 10", fields["msg"])
158	})
159}
160
161func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
162	LogAndAssertJSON(t, func(log *Logger) {
163		log.Infoln(10, 10)
164	}, func(fields Fields) {
165		assert.Equal(t, "10 10", fields["msg"])
166	})
167}
168
169func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
170	LogAndAssertJSON(t, func(log *Logger) {
171		log.Infoln(10, 10)
172	}, func(fields Fields) {
173		assert.Equal(t, "10 10", fields["msg"])
174	})
175}
176
177func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
178	LogAndAssertJSON(t, func(log *Logger) {
179		log.Info("test", 10)
180	}, func(fields Fields) {
181		assert.Equal(t, "test10", fields["msg"])
182	})
183}
184
185func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
186	LogAndAssertJSON(t, func(log *Logger) {
187		log.Info("test", "test")
188	}, func(fields Fields) {
189		assert.Equal(t, "testtest", fields["msg"])
190	})
191}
192
193func TestWithFieldsShouldAllowAssignments(t *testing.T) {
194	var buffer bytes.Buffer
195	var fields Fields
196
197	logger := New()
198	logger.Out = &buffer
199	logger.Formatter = new(JSONFormatter)
200
201	localLog := logger.WithFields(Fields{
202		"key1": "value1",
203	})
204
205	localLog.WithField("key2", "value2").Info("test")
206	err := json.Unmarshal(buffer.Bytes(), &fields)
207	assert.Nil(t, err)
208
209	assert.Equal(t, "value2", fields["key2"])
210	assert.Equal(t, "value1", fields["key1"])
211
212	buffer = bytes.Buffer{}
213	fields = Fields{}
214	localLog.Info("test")
215	err = json.Unmarshal(buffer.Bytes(), &fields)
216	assert.Nil(t, err)
217
218	_, ok := fields["key2"]
219	assert.Equal(t, false, ok)
220	assert.Equal(t, "value1", fields["key1"])
221}
222
223func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
224	LogAndAssertJSON(t, func(log *Logger) {
225		log.WithField("msg", "hello").Info("test")
226	}, func(fields Fields) {
227		assert.Equal(t, "test", fields["msg"])
228	})
229}
230
231func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
232	LogAndAssertJSON(t, func(log *Logger) {
233		log.WithField("msg", "hello").Info("test")
234	}, func(fields Fields) {
235		assert.Equal(t, "test", fields["msg"])
236		assert.Equal(t, "hello", fields["fields.msg"])
237	})
238}
239
240func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
241	LogAndAssertJSON(t, func(log *Logger) {
242		log.WithField("time", "hello").Info("test")
243	}, func(fields Fields) {
244		assert.Equal(t, "hello", fields["fields.time"])
245	})
246}
247
248func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
249	LogAndAssertJSON(t, func(log *Logger) {
250		log.WithField("level", 1).Info("test")
251	}, func(fields Fields) {
252		assert.Equal(t, "info", fields["level"])
253		assert.Equal(t, 1.0, fields["fields.level"]) // JSON has floats only
254	})
255}
256
257func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
258	LogAndAssertText(t, func(log *Logger) {
259		ll := log.WithField("herp", "derp")
260		ll.Info("hello")
261		ll.Info("bye")
262	}, func(fields map[string]string) {
263		for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
264			if _, ok := fields[fieldName]; ok {
265				t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
266			}
267		}
268	})
269}
270
271func TestWithTimeShouldOverrideTime(t *testing.T) {
272	now := time.Now().Add(24 * time.Hour)
273
274	LogAndAssertJSON(t, func(log *Logger) {
275		log.WithTime(now).Info("foobar")
276	}, func(fields Fields) {
277		assert.Equal(t, fields["time"], now.Format(time.RFC3339))
278	})
279}
280
281func TestWithTimeShouldNotOverrideFields(t *testing.T) {
282	now := time.Now().Add(24 * time.Hour)
283
284	LogAndAssertJSON(t, func(log *Logger) {
285		log.WithField("herp", "derp").WithTime(now).Info("blah")
286	}, func(fields Fields) {
287		assert.Equal(t, fields["time"], now.Format(time.RFC3339))
288		assert.Equal(t, fields["herp"], "derp")
289	})
290}
291
292func TestWithFieldShouldNotOverrideTime(t *testing.T) {
293	now := time.Now().Add(24 * time.Hour)
294
295	LogAndAssertJSON(t, func(log *Logger) {
296		log.WithTime(now).WithField("herp", "derp").Info("blah")
297	}, func(fields Fields) {
298		assert.Equal(t, fields["time"], now.Format(time.RFC3339))
299		assert.Equal(t, fields["herp"], "derp")
300	})
301}
302
303func TestTimeOverrideMultipleLogs(t *testing.T) {
304	var buffer bytes.Buffer
305	var firstFields, secondFields Fields
306
307	logger := New()
308	logger.Out = &buffer
309	formatter := new(JSONFormatter)
310	formatter.TimestampFormat = time.StampMilli
311	logger.Formatter = formatter
312
313	llog := logger.WithField("herp", "derp")
314	llog.Info("foo")
315
316	err := json.Unmarshal(buffer.Bytes(), &firstFields)
317	assert.NoError(t, err, "should have decoded first message")
318
319	buffer.Reset()
320
321	time.Sleep(10 * time.Millisecond)
322	llog.Info("bar")
323
324	err = json.Unmarshal(buffer.Bytes(), &secondFields)
325	assert.NoError(t, err, "should have decoded second message")
326
327	assert.NotEqual(t, firstFields["time"], secondFields["time"], "timestamps should not be equal")
328}
329
330func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
331
332	var buffer bytes.Buffer
333	var fields Fields
334
335	logger := New()
336	logger.Out = &buffer
337	logger.Formatter = new(JSONFormatter)
338
339	llog := logger.WithField("context", "eating raw fish")
340
341	llog.Info("looks delicious")
342
343	err := json.Unmarshal(buffer.Bytes(), &fields)
344	assert.NoError(t, err, "should have decoded first message")
345	assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
346	assert.Equal(t, fields["msg"], "looks delicious")
347	assert.Equal(t, fields["context"], "eating raw fish")
348
349	buffer.Reset()
350
351	llog.Warn("omg it is!")
352
353	err = json.Unmarshal(buffer.Bytes(), &fields)
354	assert.NoError(t, err, "should have decoded second message")
355	assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
356	assert.Equal(t, "omg it is!", fields["msg"])
357	assert.Equal(t, "eating raw fish", fields["context"])
358	assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
359
360}
361
362func TestNestedLoggingReportsCorrectCaller(t *testing.T) {
363	var buffer bytes.Buffer
364	var fields Fields
365
366	logger := New()
367	logger.Out = &buffer
368	logger.Formatter = new(JSONFormatter)
369	logger.ReportCaller = true
370
371	llog := logger.WithField("context", "eating raw fish")
372
373	llog.Info("looks delicious")
374	_, _, line, _ := runtime.Caller(0)
375
376	err := json.Unmarshal(buffer.Bytes(), &fields)
377	require.NoError(t, err, "should have decoded first message")
378	assert.Equal(t, 6, len(fields), "should have msg/time/level/func/context fields")
379	assert.Equal(t, "looks delicious", fields["msg"])
380	assert.Equal(t, "eating raw fish", fields["context"])
381	assert.Equal(t,
382		"github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"])
383	cwd, err := os.Getwd()
384	require.NoError(t, err)
385	assert.Equal(t, filepath.ToSlash(fmt.Sprintf("%s/logrus_test.go:%d", cwd, line-1)), filepath.ToSlash(fields["file"].(string)))
386
387	buffer.Reset()
388
389	logger.WithFields(Fields{
390		"Clyde": "Stubblefield",
391	}).WithFields(Fields{
392		"Jab'o": "Starks",
393	}).WithFields(Fields{
394		"uri": "https://www.youtube.com/watch?v=V5DTznu-9v0",
395	}).WithFields(Fields{
396		"func": "y drummer",
397	}).WithFields(Fields{
398		"James": "Brown",
399	}).Print("The hardest workin' man in show business")
400	_, _, line, _ = runtime.Caller(0)
401
402	err = json.Unmarshal(buffer.Bytes(), &fields)
403	assert.NoError(t, err, "should have decoded second message")
404	assert.Equal(t, 11, len(fields), "should have all builtin fields plus foo,bar,baz,...")
405	assert.Equal(t, "Stubblefield", fields["Clyde"])
406	assert.Equal(t, "Starks", fields["Jab'o"])
407	assert.Equal(t, "https://www.youtube.com/watch?v=V5DTznu-9v0", fields["uri"])
408	assert.Equal(t, "y drummer", fields["fields.func"])
409	assert.Equal(t, "Brown", fields["James"])
410	assert.Equal(t, "The hardest workin' man in show business", fields["msg"])
411	assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
412	assert.Equal(t,
413		"github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"])
414	require.NoError(t, err)
415	assert.Equal(t, filepath.ToSlash(fmt.Sprintf("%s/logrus_test.go:%d", cwd, line-1)), filepath.ToSlash(fields["file"].(string)))
416
417	logger.ReportCaller = false // return to default value
418}
419
420func logLoop(iterations int, reportCaller bool) {
421	var buffer bytes.Buffer
422
423	logger := New()
424	logger.Out = &buffer
425	logger.Formatter = new(JSONFormatter)
426	logger.ReportCaller = reportCaller
427
428	for i := 0; i < iterations; i++ {
429		logger.Infof("round %d of %d", i, iterations)
430	}
431}
432
433// Assertions for upper bounds to reporting overhead
434func TestCallerReportingOverhead(t *testing.T) {
435	iterations := 5000
436	before := time.Now()
437	logLoop(iterations, false)
438	during := time.Now()
439	logLoop(iterations, true)
440	after := time.Now()
441
442	elapsedNotReporting := during.Sub(before).Nanoseconds()
443	elapsedReporting := after.Sub(during).Nanoseconds()
444
445	maxDelta := 1 * time.Second
446	assert.WithinDuration(t, during, before, maxDelta,
447		"%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)",
448		iterations, maxDelta.Seconds(), elapsedNotReporting)
449	assert.WithinDuration(t, after, during, maxDelta,
450		"%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)",
451		iterations, maxDelta.Seconds(), elapsedReporting)
452}
453
454// benchmarks for both with and without caller-function reporting
455func BenchmarkWithoutCallerTracing(b *testing.B) {
456	for i := 0; i < b.N; i++ {
457		logLoop(1000, false)
458	}
459}
460
461func BenchmarkWithCallerTracing(b *testing.B) {
462	for i := 0; i < b.N; i++ {
463		logLoop(1000, true)
464	}
465}
466
467func TestConvertLevelToString(t *testing.T) {
468	assert.Equal(t, "trace", TraceLevel.String())
469	assert.Equal(t, "debug", DebugLevel.String())
470	assert.Equal(t, "info", InfoLevel.String())
471	assert.Equal(t, "warning", WarnLevel.String())
472	assert.Equal(t, "error", ErrorLevel.String())
473	assert.Equal(t, "fatal", FatalLevel.String())
474	assert.Equal(t, "panic", PanicLevel.String())
475}
476
477func TestParseLevel(t *testing.T) {
478	l, err := ParseLevel("panic")
479	assert.Nil(t, err)
480	assert.Equal(t, PanicLevel, l)
481
482	l, err = ParseLevel("PANIC")
483	assert.Nil(t, err)
484	assert.Equal(t, PanicLevel, l)
485
486	l, err = ParseLevel("fatal")
487	assert.Nil(t, err)
488	assert.Equal(t, FatalLevel, l)
489
490	l, err = ParseLevel("FATAL")
491	assert.Nil(t, err)
492	assert.Equal(t, FatalLevel, l)
493
494	l, err = ParseLevel("error")
495	assert.Nil(t, err)
496	assert.Equal(t, ErrorLevel, l)
497
498	l, err = ParseLevel("ERROR")
499	assert.Nil(t, err)
500	assert.Equal(t, ErrorLevel, l)
501
502	l, err = ParseLevel("warn")
503	assert.Nil(t, err)
504	assert.Equal(t, WarnLevel, l)
505
506	l, err = ParseLevel("WARN")
507	assert.Nil(t, err)
508	assert.Equal(t, WarnLevel, l)
509
510	l, err = ParseLevel("warning")
511	assert.Nil(t, err)
512	assert.Equal(t, WarnLevel, l)
513
514	l, err = ParseLevel("WARNING")
515	assert.Nil(t, err)
516	assert.Equal(t, WarnLevel, l)
517
518	l, err = ParseLevel("info")
519	assert.Nil(t, err)
520	assert.Equal(t, InfoLevel, l)
521
522	l, err = ParseLevel("INFO")
523	assert.Nil(t, err)
524	assert.Equal(t, InfoLevel, l)
525
526	l, err = ParseLevel("debug")
527	assert.Nil(t, err)
528	assert.Equal(t, DebugLevel, l)
529
530	l, err = ParseLevel("DEBUG")
531	assert.Nil(t, err)
532	assert.Equal(t, DebugLevel, l)
533
534	l, err = ParseLevel("trace")
535	assert.Nil(t, err)
536	assert.Equal(t, TraceLevel, l)
537
538	l, err = ParseLevel("TRACE")
539	assert.Nil(t, err)
540	assert.Equal(t, TraceLevel, l)
541
542	_, err = ParseLevel("invalid")
543	assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
544}
545
546func TestLevelString(t *testing.T) {
547	var loggerlevel Level
548	loggerlevel = 32000
549
550	_ = loggerlevel.String()
551}
552
553func TestGetSetLevelRace(t *testing.T) {
554	wg := sync.WaitGroup{}
555	for i := 0; i < 100; i++ {
556		wg.Add(1)
557		go func(i int) {
558			defer wg.Done()
559			if i%2 == 0 {
560				SetLevel(InfoLevel)
561			} else {
562				GetLevel()
563			}
564		}(i)
565
566	}
567	wg.Wait()
568}
569
570func TestLoggingRace(t *testing.T) {
571	logger := New()
572
573	var wg sync.WaitGroup
574	wg.Add(100)
575
576	for i := 0; i < 100; i++ {
577		go func() {
578			logger.Info("info")
579			wg.Done()
580		}()
581	}
582	wg.Wait()
583}
584
585func TestLoggingRaceWithHooksOnEntry(t *testing.T) {
586	logger := New()
587	hook := new(ModifyHook)
588	logger.AddHook(hook)
589	entry := logger.WithField("context", "clue")
590
591	var (
592		wg    sync.WaitGroup
593		mtx   sync.Mutex
594		start bool
595	)
596
597	cond := sync.NewCond(&mtx)
598
599	wg.Add(100)
600
601	for i := 0; i < 50; i++ {
602		go func() {
603			cond.L.Lock()
604			for !start {
605				cond.Wait()
606			}
607			cond.L.Unlock()
608			for j := 0; j < 100; j++ {
609				entry.Info("info")
610			}
611			wg.Done()
612		}()
613	}
614
615	for i := 0; i < 50; i++ {
616		go func() {
617			cond.L.Lock()
618			for !start {
619				cond.Wait()
620			}
621			cond.L.Unlock()
622			for j := 0; j < 100; j++ {
623				entry.WithField("another field", "with some data").Info("info")
624			}
625			wg.Done()
626		}()
627	}
628
629	cond.L.Lock()
630	start = true
631	cond.L.Unlock()
632	cond.Broadcast()
633	wg.Wait()
634}
635
636func TestReplaceHooks(t *testing.T) {
637	old, cur := &TestHook{}, &TestHook{}
638
639	logger := New()
640	logger.SetOutput(ioutil.Discard)
641	logger.AddHook(old)
642
643	hooks := make(LevelHooks)
644	hooks.Add(cur)
645	replaced := logger.ReplaceHooks(hooks)
646
647	logger.Info("test")
648
649	assert.Equal(t, old.Fired, false)
650	assert.Equal(t, cur.Fired, true)
651
652	logger.ReplaceHooks(replaced)
653	logger.Info("test")
654	assert.Equal(t, old.Fired, true)
655}
656
657// Compile test
658func TestLogrusInterfaces(t *testing.T) {
659	var buffer bytes.Buffer
660	// This verifies FieldLogger and Ext1FieldLogger work as designed.
661	// Please don't use them. Use Logger and Entry directly.
662	fn := func(xl Ext1FieldLogger) {
663		var l FieldLogger = xl
664		b := l.WithField("key", "value")
665		b.Debug("Test")
666	}
667	// test logger
668	logger := New()
669	logger.Out = &buffer
670	fn(logger)
671
672	// test Entry
673	e := logger.WithField("another", "value")
674	fn(e)
675}
676
677// Implements io.Writer using channels for synchronization, so we can wait on
678// the Entry.Writer goroutine to write in a non-racey way. This does assume that
679// there is a single call to Logger.Out for each message.
680type channelWriter chan []byte
681
682func (cw channelWriter) Write(p []byte) (int, error) {
683	cw <- p
684	return len(p), nil
685}
686
687func TestEntryWriter(t *testing.T) {
688	cw := channelWriter(make(chan []byte, 1))
689	log := New()
690	log.Out = cw
691	log.Formatter = new(JSONFormatter)
692	_, err := log.WithField("foo", "bar").WriterLevel(WarnLevel).Write([]byte("hello\n"))
693	if err != nil {
694		t.Error("unexecpted error", err)
695	}
696
697	bs := <-cw
698	var fields Fields
699	err = json.Unmarshal(bs, &fields)
700	assert.Nil(t, err)
701	assert.Equal(t, fields["foo"], "bar")
702	assert.Equal(t, fields["level"], "warning")
703}
704
705func TestLogLevelEnabled(t *testing.T) {
706	log := New()
707	log.SetLevel(PanicLevel)
708	assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
709	assert.Equal(t, false, log.IsLevelEnabled(FatalLevel))
710	assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel))
711	assert.Equal(t, false, log.IsLevelEnabled(WarnLevel))
712	assert.Equal(t, false, log.IsLevelEnabled(InfoLevel))
713	assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
714	assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
715
716	log.SetLevel(FatalLevel)
717	assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
718	assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
719	assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel))
720	assert.Equal(t, false, log.IsLevelEnabled(WarnLevel))
721	assert.Equal(t, false, log.IsLevelEnabled(InfoLevel))
722	assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
723	assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
724
725	log.SetLevel(ErrorLevel)
726	assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
727	assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
728	assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
729	assert.Equal(t, false, log.IsLevelEnabled(WarnLevel))
730	assert.Equal(t, false, log.IsLevelEnabled(InfoLevel))
731	assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
732	assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
733
734	log.SetLevel(WarnLevel)
735	assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
736	assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
737	assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
738	assert.Equal(t, true, log.IsLevelEnabled(WarnLevel))
739	assert.Equal(t, false, log.IsLevelEnabled(InfoLevel))
740	assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
741	assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
742
743	log.SetLevel(InfoLevel)
744	assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
745	assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
746	assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
747	assert.Equal(t, true, log.IsLevelEnabled(WarnLevel))
748	assert.Equal(t, true, log.IsLevelEnabled(InfoLevel))
749	assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
750	assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
751
752	log.SetLevel(DebugLevel)
753	assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
754	assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
755	assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
756	assert.Equal(t, true, log.IsLevelEnabled(WarnLevel))
757	assert.Equal(t, true, log.IsLevelEnabled(InfoLevel))
758	assert.Equal(t, true, log.IsLevelEnabled(DebugLevel))
759	assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
760
761	log.SetLevel(TraceLevel)
762	assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
763	assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
764	assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
765	assert.Equal(t, true, log.IsLevelEnabled(WarnLevel))
766	assert.Equal(t, true, log.IsLevelEnabled(InfoLevel))
767	assert.Equal(t, true, log.IsLevelEnabled(DebugLevel))
768	assert.Equal(t, true, log.IsLevelEnabled(TraceLevel))
769}
770
771func TestReportCallerOnTextFormatter(t *testing.T) {
772	l := New()
773
774	l.Formatter.(*TextFormatter).ForceColors = true
775	l.Formatter.(*TextFormatter).DisableColors = false
776	l.WithFields(Fields{"func": "func", "file": "file"}).Info("test")
777
778	l.Formatter.(*TextFormatter).ForceColors = false
779	l.Formatter.(*TextFormatter).DisableColors = true
780	l.WithFields(Fields{"func": "func", "file": "file"}).Info("test")
781}
782
783func TestSetReportCallerRace(t *testing.T) {
784	l := New()
785	l.Out = ioutil.Discard
786	l.SetReportCaller(true)
787
788	var wg sync.WaitGroup
789	wg.Add(100)
790
791	for i := 0; i < 100; i++ {
792		go func() {
793			l.Error("Some Error")
794			wg.Done()
795		}()
796	}
797	wg.Wait()
798}
799