1package zerolog 2 3import ( 4 "bytes" 5 "io/ioutil" 6 "testing" 7) 8 9var ( 10 levelNameHook = HookFunc(func(e *Event, level Level, msg string) { 11 levelName := level.String() 12 if level == NoLevel { 13 levelName = "nolevel" 14 } 15 e.Str("level_name", levelName) 16 }) 17 simpleHook = HookFunc(func(e *Event, level Level, msg string) { 18 e.Bool("has_level", level != NoLevel) 19 e.Str("test", "logged") 20 }) 21 copyHook = HookFunc(func(e *Event, level Level, msg string) { 22 hasLevel := level != NoLevel 23 e.Bool("copy_has_level", hasLevel) 24 if hasLevel { 25 e.Str("copy_level", level.String()) 26 } 27 e.Str("copy_msg", msg) 28 }) 29 nopHook = HookFunc(func(e *Event, level Level, message string) { 30 }) 31 discardHook = HookFunc(func(e *Event, level Level, message string) { 32 e.Discard() 33 }) 34) 35 36func TestHook(t *testing.T) { 37 tests := []struct { 38 name string 39 want string 40 test func(log Logger) 41 }{ 42 {"Message", `{"level_name":"nolevel","message":"test message"}` + "\n", func(log Logger) { 43 log = log.Hook(levelNameHook) 44 log.Log().Msg("test message") 45 }}, 46 {"NoLevel", `{"level_name":"nolevel"}` + "\n", func(log Logger) { 47 log = log.Hook(levelNameHook) 48 log.Log().Msg("") 49 }}, 50 {"Print", `{"level":"debug","level_name":"debug"}` + "\n", func(log Logger) { 51 log = log.Hook(levelNameHook) 52 log.Print("") 53 }}, 54 {"Error", `{"level":"error","level_name":"error"}` + "\n", func(log Logger) { 55 log = log.Hook(levelNameHook) 56 log.Error().Msg("") 57 }}, 58 {"Copy/1", `{"copy_has_level":false,"copy_msg":""}` + "\n", func(log Logger) { 59 log = log.Hook(copyHook) 60 log.Log().Msg("") 61 }}, 62 {"Copy/2", `{"level":"info","copy_has_level":true,"copy_level":"info","copy_msg":"a message","message":"a message"}` + "\n", func(log Logger) { 63 log = log.Hook(copyHook) 64 log.Info().Msg("a message") 65 }}, 66 {"Multi", `{"level":"error","level_name":"error","has_level":true,"test":"logged"}` + "\n", func(log Logger) { 67 log = log.Hook(levelNameHook).Hook(simpleHook) 68 log.Error().Msg("") 69 }}, 70 {"Multi/Message", `{"level":"error","level_name":"error","has_level":true,"test":"logged","message":"a message"}` + "\n", func(log Logger) { 71 log = log.Hook(levelNameHook).Hook(simpleHook) 72 log.Error().Msg("a message") 73 }}, 74 {"Output/single/pre", `{"level":"error","level_name":"error"}` + "\n", func(log Logger) { 75 ignored := &bytes.Buffer{} 76 log = New(ignored).Hook(levelNameHook).Output(log.w) 77 log.Error().Msg("") 78 }}, 79 {"Output/single/post", `{"level":"error","level_name":"error"}` + "\n", func(log Logger) { 80 ignored := &bytes.Buffer{} 81 log = New(ignored).Output(log.w).Hook(levelNameHook) 82 log.Error().Msg("") 83 }}, 84 {"Output/multi/pre", `{"level":"error","level_name":"error","has_level":true,"test":"logged"}` + "\n", func(log Logger) { 85 ignored := &bytes.Buffer{} 86 log = New(ignored).Hook(levelNameHook).Hook(simpleHook).Output(log.w) 87 log.Error().Msg("") 88 }}, 89 {"Output/multi/post", `{"level":"error","level_name":"error","has_level":true,"test":"logged"}` + "\n", func(log Logger) { 90 ignored := &bytes.Buffer{} 91 log = New(ignored).Output(log.w).Hook(levelNameHook).Hook(simpleHook) 92 log.Error().Msg("") 93 }}, 94 {"Output/mixed", `{"level":"error","level_name":"error","has_level":true,"test":"logged"}` + "\n", func(log Logger) { 95 ignored := &bytes.Buffer{} 96 log = New(ignored).Hook(levelNameHook).Output(log.w).Hook(simpleHook) 97 log.Error().Msg("") 98 }}, 99 {"With/single/pre", `{"level":"error","with":"pre","level_name":"error"}` + "\n", func(log Logger) { 100 log = log.Hook(levelNameHook).With().Str("with", "pre").Logger() 101 log.Error().Msg("") 102 }}, 103 {"With/single/post", `{"level":"error","with":"post","level_name":"error"}` + "\n", func(log Logger) { 104 log = log.With().Str("with", "post").Logger().Hook(levelNameHook) 105 log.Error().Msg("") 106 }}, 107 {"With/multi/pre", `{"level":"error","with":"pre","level_name":"error","has_level":true,"test":"logged"}` + "\n", func(log Logger) { 108 log = log.Hook(levelNameHook).Hook(simpleHook).With().Str("with", "pre").Logger() 109 log.Error().Msg("") 110 }}, 111 {"With/multi/post", `{"level":"error","with":"post","level_name":"error","has_level":true,"test":"logged"}` + "\n", func(log Logger) { 112 log = log.With().Str("with", "post").Logger().Hook(levelNameHook).Hook(simpleHook) 113 log.Error().Msg("") 114 }}, 115 {"With/mixed", `{"level":"error","with":"mixed","level_name":"error","has_level":true,"test":"logged"}` + "\n", func(log Logger) { 116 log = log.Hook(levelNameHook).With().Str("with", "mixed").Logger().Hook(simpleHook) 117 log.Error().Msg("") 118 }}, 119 {"Discard", "", func(log Logger) { 120 log = log.Hook(discardHook) 121 log.Log().Msg("test message") 122 }}, 123 {"None", `{"level":"error"}` + "\n", func(log Logger) { 124 log.Error().Msg("") 125 }}, 126 } 127 for _, tt := range tests { 128 tt := tt 129 t.Run(tt.name, func(t *testing.T) { 130 out := &bytes.Buffer{} 131 log := New(out) 132 tt.test(log) 133 if got, want := decodeIfBinaryToString(out.Bytes()), tt.want; got != want { 134 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) 135 } 136 }) 137 } 138} 139 140func BenchmarkHooks(b *testing.B) { 141 logger := New(ioutil.Discard) 142 b.ResetTimer() 143 b.Run("Nop/Single", func(b *testing.B) { 144 log := logger.Hook(nopHook) 145 b.RunParallel(func(pb *testing.PB) { 146 for pb.Next() { 147 log.Log().Msg("") 148 } 149 }) 150 }) 151 b.Run("Nop/Multi", func(b *testing.B) { 152 log := logger.Hook(nopHook).Hook(nopHook) 153 b.RunParallel(func(pb *testing.PB) { 154 for pb.Next() { 155 log.Log().Msg("") 156 } 157 }) 158 }) 159 b.Run("Simple", func(b *testing.B) { 160 log := logger.Hook(simpleHook) 161 b.RunParallel(func(pb *testing.PB) { 162 for pb.Next() { 163 log.Log().Msg("") 164 } 165 }) 166 }) 167} 168