github.com/Laisky/zap@v1.27.0/zapcore/lazy_with_test.go (about) 1 // Copyright (c) 2023 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package zapcore_test 22 23 import ( 24 "sync/atomic" 25 "testing" 26 27 "github.com/Laisky/zap/zapcore" 28 "github.com/Laisky/zap/zaptest/observer" 29 "github.com/stretchr/testify/assert" 30 ) 31 32 type proxyCore struct { 33 zapcore.Core 34 35 withCount atomic.Int64 36 checkCount atomic.Int64 37 } 38 39 func newProxyCore(inner zapcore.Core) *proxyCore { 40 return &proxyCore{Core: inner} 41 } 42 43 func (p *proxyCore) With(fields []zapcore.Field) zapcore.Core { 44 p.withCount.Add(1) 45 return p.Core.With(fields) 46 } 47 48 func (p *proxyCore) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { 49 p.checkCount.Add(1) 50 return p.Core.Check(e, ce) 51 } 52 53 func withLazyCore(f func(zapcore.Core, *proxyCore, *observer.ObservedLogs), initialFields ...zapcore.Field) { 54 infoLogger, infoLogs := observer.New(zapcore.InfoLevel) 55 proxyCore := newProxyCore(infoLogger) 56 lazyCore := zapcore.NewLazyWith(proxyCore, initialFields) 57 f(lazyCore, proxyCore, infoLogs) 58 } 59 60 func TestLazyCore(t *testing.T) { 61 tests := []struct { 62 name string 63 entries []zapcore.Entry 64 initialFields []zapcore.Field 65 withChains [][]zapcore.Field 66 wantLogs []observer.LoggedEntry 67 }{ 68 { 69 name: "no logging, no with, inner core with never called, inner core check never called", 70 wantLogs: []observer.LoggedEntry{}, 71 }, 72 { 73 name: "2 logs, 1 dropped, no with, inner core with called once, inner core check never called", 74 entries: []zapcore.Entry{ 75 {Level: zapcore.DebugLevel, Message: "log-at-debug"}, 76 {Level: zapcore.WarnLevel, Message: "log-at-warn"}, 77 }, 78 wantLogs: []observer.LoggedEntry{ 79 { 80 Entry: zapcore.Entry{ 81 Level: zapcore.WarnLevel, 82 Message: "log-at-warn", 83 }, 84 Context: []zapcore.Field{}, 85 }, 86 }, 87 }, 88 { 89 name: "no logs, 2-chained with, inner core with called once, inner core check never called", 90 withChains: [][]zapcore.Field{ 91 {makeInt64Field("a", 11), makeInt64Field("b", 22)}, 92 {makeInt64Field("c", 33), makeInt64Field("d", 44)}, 93 }, 94 wantLogs: []observer.LoggedEntry{}, 95 }, 96 { 97 name: "2 logs, 1 dropped, 2-chained with, inner core with called once, inner core check never called", 98 entries: []zapcore.Entry{ 99 {Level: zapcore.DebugLevel, Message: "log-at-debug"}, 100 {Level: zapcore.WarnLevel, Message: "log-at-warn"}, 101 }, 102 withChains: [][]zapcore.Field{ 103 {makeInt64Field("a", 11), makeInt64Field("b", 22)}, 104 {makeInt64Field("c", 33), makeInt64Field("d", 44)}, 105 }, 106 wantLogs: []observer.LoggedEntry{ 107 { 108 Entry: zapcore.Entry{ 109 Level: zapcore.WarnLevel, 110 Message: "log-at-warn", 111 }, 112 Context: []zapcore.Field{ 113 makeInt64Field("a", 11), 114 makeInt64Field("b", 22), 115 makeInt64Field("c", 33), 116 makeInt64Field("d", 44), 117 }, 118 }, 119 }, 120 }, 121 } 122 for _, tt := range tests { 123 t.Run(tt.name, func(t *testing.T) { 124 withLazyCore(func(lazy zapcore.Core, proxy *proxyCore, logs *observer.ObservedLogs) { 125 checkCounts := func(withCount int64, msg string) { 126 assert.Equal(t, withCount, proxy.withCount.Load(), msg) 127 } 128 checkCounts(0, "expected no with calls because the logger is not used yet") 129 130 for _, chain := range tt.withChains { 131 lazy = lazy.With(chain) 132 } 133 if len(tt.withChains) > 0 { 134 checkCounts(1, "expected with calls because the logger was with-chained") 135 } else { 136 checkCounts(0, "expected no with calls because the logger is not used yet") 137 } 138 139 for _, ent := range tt.entries { 140 if ce := lazy.Check(ent, nil); ce != nil { 141 ce.Write() 142 } 143 } 144 if len(tt.entries) > 0 || len(tt.withChains) > 0 { 145 checkCounts(1, "expected with calls because the logger had entries or with chains") 146 } else { 147 checkCounts(0, "expected no with calls because the logger is not used yet") 148 } 149 assert.Zero(t, proxy.checkCount.Load(), "expected no check calls because the inner core is copied") 150 assert.Equal(t, tt.wantLogs, logs.AllUntimed()) 151 }, tt.initialFields...) 152 }) 153 } 154 }