github.com/facebookincubator/go-belt@v0.0.0-20230703220935-39cd348f1a38/tool/logger/tests/implementation_test.go (about) 1 // Copyright 2022 Meta Platforms, Inc. and affiliates. 2 // 3 // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 // 5 // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 // 7 // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 // 9 // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 // 11 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 13 package tests 14 15 import ( 16 "bytes" 17 "fmt" 18 "log" 19 "net/url" 20 "strings" 21 "sync" 22 "testing" 23 24 "github.com/facebookincubator/go-belt" 25 "github.com/facebookincubator/go-belt/pkg/field" 26 "github.com/facebookincubator/go-belt/tool/logger/implementation/logrus" 27 "github.com/facebookincubator/go-belt/tool/logger/implementation/stdlib" 28 "github.com/facebookincubator/go-belt/tool/logger/implementation/zap" 29 "github.com/facebookincubator/go-belt/tool/logger/types" 30 upstreamlogrus "github.com/sirupsen/logrus" 31 upstreamzap "go.uber.org/zap" 32 ) 33 34 type zapBuffer struct { 35 bytes.Buffer 36 } 37 38 func (buf *zapBuffer) Close() error { 39 return nil 40 } 41 42 func (buf *zapBuffer) Sync() error { 43 return nil 44 } 45 46 type logger struct { 47 Name string 48 Logger types.Logger 49 Output *bytes.Buffer 50 } 51 52 func getImplementations(t *testing.T) []logger { 53 var result []logger 54 55 // stdlib 56 { 57 var buf bytes.Buffer 58 result = append(result, logger{ 59 Name: "stdlib", 60 Logger: stdlib.New(log.New(&buf, "", 0), types.LevelTrace), 61 Output: &buf, 62 }) 63 } 64 65 // zap 66 { 67 var buf zapBuffer 68 err := upstreamzap.RegisterSink("buf", func(*url.URL) (upstreamzap.Sink, error) { 69 return &buf, nil 70 }) 71 if err != nil { 72 t.Fatal(err) 73 } 74 75 zapCfg := upstreamzap.NewDevelopmentConfig() 76 zapCfg.Encoding = "json" 77 zapCfg.OutputPaths = []string{"buf:"} 78 zapCfg.Level = upstreamzap.NewAtomicLevelAt(zap.LevelToZap(types.LevelTrace)) 79 zapLogger, err := zapCfg.Build() 80 if err != nil { 81 t.Fatal(err) 82 } 83 result = append(result, logger{ 84 Name: "zap", 85 Logger: zap.New(zapLogger), 86 Output: &buf.Buffer, 87 }) 88 } 89 90 // logrus 91 { 92 var buf bytes.Buffer 93 logrusLogger := upstreamlogrus.New() 94 logrusLogger.Out = &buf 95 logrusLogger.Level = logrus.LevelToLogrus(types.LevelTrace) 96 result = append(result, logger{ 97 Name: "logrus", 98 Logger: logrus.New(logrusLogger), 99 Output: &buf, 100 }) 101 } 102 103 // glog 104 { 105 // the upstream glog logger does not support diverting the output to a buffer 106 } 107 108 return result 109 } 110 111 func TestImplementations(t *testing.T) { 112 for _, l := range getImplementations(t) { 113 t.Run(l.Name, func(t *testing.T) { 114 t.Run("race-check", func(t *testing.T) { 115 l.Output.Reset() 116 117 // this test supposed to be ran with "-race" 118 var wg sync.WaitGroup 119 wg.Add(1) 120 go func() { 121 defer wg.Done() 122 l.Logger.Errorf("test0") 123 }() 124 wg.Add(1) 125 go func() { 126 defer wg.Done() 127 l.Logger.Errorf("test1") 128 }() 129 wg.Wait() 130 l.Logger.Flush() 131 }) 132 133 t.Run("Errorf", func(t *testing.T) { 134 l.Output.Reset() 135 l.Logger.Errorf("unit-test") 136 l.Logger.Flush() 137 if !strings.Contains(l.Output.String(), "unit-test") { 138 t.Fatalf("logger %s did not print an error using Errorf", l.Name) 139 } 140 }) 141 142 t.Run("Error", func(t *testing.T) { 143 l.Output.Reset() 144 l.Logger.Error(fmt.Errorf("unit-test")) 145 l.Logger.Flush() 146 if !strings.Contains(l.Output.String(), "unit-test") { 147 t.Fatalf("logger %s did not print an error using Error", l.Name) 148 } 149 }) 150 151 t.Run("Error-with-PreHook", func(t *testing.T) { 152 l.Output.Reset() 153 logger := l.Logger.WithPreHooks(addExtraFieldPreHook{}) 154 logger.Error(fmt.Errorf("unit-test")) 155 logger.Flush() 156 if !strings.Contains(l.Output.String(), "unit-test") { 157 t.Fatalf("logger %s did not print an error using Error with the PreHook", l.Name) 158 } 159 }) 160 161 t.Run("WithMessagePrefix", func(t *testing.T) { 162 l.Output.Reset() 163 logger := l.Logger.WithMessagePrefix("specialMagic") 164 logger.Error(fmt.Errorf("unit-test")) 165 logger.Flush() 166 if !strings.Contains(l.Output.String(), "specialMagic") { 167 t.Fatalf("logger %s did not print the special magic string", l.Name) 168 } 169 }) 170 }) 171 } 172 } 173 174 type addExtraFieldPreHook struct{} 175 176 var addExtraFieldPreHookResult = types.PreHookResult{ 177 ExtraFields: &field.Field{ 178 Key: "some-key", 179 Value: "some-value", 180 }, 181 } 182 183 func (addExtraFieldPreHook) ProcessInput(belt.TraceIDs, types.Level, ...any) types.PreHookResult { 184 return addExtraFieldPreHookResult 185 } 186 187 func (addExtraFieldPreHook) ProcessInputf(belt.TraceIDs, types.Level, string, ...any) types.PreHookResult { 188 return addExtraFieldPreHookResult 189 } 190 191 func (addExtraFieldPreHook) ProcessInputFields(belt.TraceIDs, types.Level, string, field.AbstractFields) types.PreHookResult { 192 return addExtraFieldPreHookResult 193 }