Skip to content

Commit 5ae3ca9

Browse files
committed
[FAB-15432] improve level enabled checks
Change-Id: Ia5fb43fa69aa2085cb74008a55ce92c7f561054b Signed-off-by: Dereck Luo <Chongxin.Luo@ibm.com> Signed-off-by: Matthew Sykes <sykesmat@us.ibm.com>
1 parent 228387d commit 5ae3ca9

File tree

5 files changed

+100
-10
lines changed

5 files changed

+100
-10
lines changed

common/flogging/loggerlevels.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ import (
1919

2020
// LoggerLevels tracks the logging level of named loggers.
2121
type LoggerLevels struct {
22+
mutex sync.RWMutex
23+
levelCache map[string]zapcore.Level
24+
specs map[string]zapcore.Level
2225
defaultLevel zapcore.Level
23-
24-
mutex sync.RWMutex
25-
levelCache map[string]zapcore.Level
26-
specs map[string]zapcore.Level
26+
minLevel zapcore.Level
2727
}
2828

2929
// DefaultLevel returns the default logging level for loggers that do not have
@@ -80,6 +80,14 @@ func (l *LoggerLevels) ActivateSpec(spec string) error {
8080
}
8181
}
8282

83+
minLevel := defaultLevel
84+
for _, lvl := range specs {
85+
if lvl < minLevel {
86+
minLevel = lvl
87+
}
88+
}
89+
90+
l.minLevel = minLevel
8391
l.defaultLevel = defaultLevel
8492
l.specs = specs
8593
l.levelCache = map[string]zapcore.Level{}
@@ -155,3 +163,12 @@ func (l *LoggerLevels) Spec() string {
155163

156164
return strings.Join(fields, ":")
157165
}
166+
167+
// Enabled function is an enabled check that evaluates the minimum active logging level.
168+
// It serves as a fast check before the (relatively) expensive Check call in the core.
169+
func (l *LoggerLevels) Enabled(lvl zapcore.Level) bool {
170+
l.mutex.RLock()
171+
enabled := l.minLevel.Enabled(lvl)
172+
l.mutex.RUnlock()
173+
return enabled
174+
}

common/flogging/loggerlevels_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package flogging_test
88

99
import (
1010
"errors"
11+
"strconv"
1112
"testing"
1213

1314
"github.com/hyperledger/fabric/common/flogging"
@@ -155,3 +156,37 @@ func TestSpec(t *testing.T) {
155156
assert.Equal(t, tc.output, ll.Spec())
156157
}
157158
}
159+
160+
func TestEnabled(t *testing.T) {
161+
var tests = []struct {
162+
spec string
163+
enabledAt zapcore.Level
164+
}{
165+
{spec: "payload", enabledAt: flogging.PayloadLevel},
166+
{spec: "debug", enabledAt: zapcore.DebugLevel},
167+
{spec: "info", enabledAt: zapcore.InfoLevel},
168+
{spec: "warn", enabledAt: zapcore.WarnLevel},
169+
{spec: "panic", enabledAt: zapcore.PanicLevel},
170+
{spec: "fatal", enabledAt: zapcore.FatalLevel},
171+
{spec: "fatal:a=debug", enabledAt: zapcore.DebugLevel},
172+
{spec: "a=fatal:b=warn", enabledAt: zapcore.InfoLevel},
173+
{spec: "a=warn", enabledAt: zapcore.InfoLevel},
174+
{spec: "a=debug", enabledAt: zapcore.DebugLevel},
175+
}
176+
177+
for i, tc := range tests {
178+
t.Run(strconv.Itoa(i), func(t *testing.T) {
179+
ll := &flogging.LoggerLevels{}
180+
err := ll.ActivateSpec(tc.spec)
181+
assert.NoError(t, err)
182+
183+
for i := flogging.PayloadLevel; i <= zapcore.FatalLevel; i++ {
184+
if tc.enabledAt <= i {
185+
assert.Truef(t, ll.Enabled(i), "expected level %s and spec %s to be enabled", zapcore.Level(i), tc.spec)
186+
} else {
187+
assert.False(t, ll.Enabled(i), "expected level %s and spec %s to be disabled", zapcore.Level(i), tc.spec)
188+
}
189+
}
190+
})
191+
}
192+
}

common/flogging/logging.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,9 @@ func (s *Logging) ZapLogger(name string) *zap.Logger {
209209
panic(fmt.Sprintf("invalid logger name: %s", name))
210210
}
211211

212-
// always return true here because the core's Check()
213-
// method computes the level for the logger name based
214-
// on the active logging spec
215-
levelEnabler := zap.LevelEnablerFunc(func(l zapcore.Level) bool { return true })
216-
217212
s.mutex.RLock()
218213
core := &Core{
219-
LevelEnabler: levelEnabler,
214+
LevelEnabler: s.LoggerLevels,
220215
Levels: s.LoggerLevels,
221216
Encoders: map[Encoding]zapcore.Encoder{
222217
JSON: zapcore.NewJSONEncoder(s.encoderConfig),

common/flogging/logging_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,18 @@ func TestCheck(t *testing.T) {
133133
l.Check(zapcore.Entry{}, nil)
134134
assert.Equal(t, 1, observer.CheckCallCount())
135135
}
136+
137+
func TestLoggerCoreCheck(t *testing.T) {
138+
logging, err := flogging.New(flogging.Config{})
139+
assert.NoError(t, err)
140+
141+
logger := logging.ZapLogger("foo")
142+
143+
err = logging.ActivateSpec("info")
144+
assert.NoError(t, err)
145+
assert.False(t, logger.Core().Enabled(zapcore.DebugLevel), "debug should not be enabled at info level")
146+
147+
err = logging.ActivateSpec("debug")
148+
assert.NoError(t, err)
149+
assert.True(t, logger.Core().Enabled(zapcore.DebugLevel), "debug should now be enabled at debug level")
150+
}

common/flogging/zap_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/hyperledger/fabric/common/flogging"
1616
"github.com/hyperledger/fabric/common/flogging/fabenc"
17+
"github.com/hyperledger/fabric/common/flogging/mock"
1718
"github.com/stretchr/testify/assert"
1819
"go.uber.org/zap"
1920
"go.uber.org/zap/zapcore"
@@ -308,3 +309,30 @@ func TestGRPCLogger(t *testing.T) {
308309
callWrapper(gl, "message")
309310
assert.Equal(t, "grpc DEBUG TestGRPCLogger message\n", buf.String())
310311
}
312+
313+
// FAB-15432
314+
//
315+
// When the FabricLogger is used, the zap Core check function should not be
316+
// driven if the minimum log level is above the level we are logging at.
317+
// In other words, with a log spec of "info", logging at Debug should prevent
318+
// a call to Check while logging at Info will not.
319+
func TestEnabledLevelCheck(t *testing.T) {
320+
buf := &bytes.Buffer{}
321+
logging, err := flogging.New(flogging.Config{
322+
LogSpec: "info",
323+
Writer: buf,
324+
})
325+
assert.NoError(t, err)
326+
327+
fakeObserver := &mock.Observer{}
328+
logging.SetObserver(fakeObserver)
329+
330+
logger := logging.ZapLogger("foo")
331+
fabricLogger := flogging.NewFabricLogger(logger)
332+
333+
fabricLogger.Debug("debug message")
334+
assert.Equal(t, 0, fakeObserver.CheckCallCount(), "Check should not have been called")
335+
336+
fabricLogger.Info("info message")
337+
assert.Equal(t, 1, fakeObserver.CheckCallCount(), "Check should have been called")
338+
}

0 commit comments

Comments
 (0)