Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement BlockSelectors for level debug #125

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions logp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ import (
// Config contains the configuration options for the logger. To create a Config
// from a common.Config use logp/config.Build.
type Config struct {
Beat string `config:",ignore"` // Name of the Beat (for default file name).
Level Level `config:"level"` // Logging level (error, warning, info, debug).
Selectors []string `config:"selectors"` // Selectors for debug level logging.
Beat string `config:",ignore"` // Name of the Beat (for default file name).
Level Level `config:"level"` // Logging level (error, warning, info, debug).
Selectors []string `config:"selectors"` // Selectors for debug level logging.
BlockSelectors []string `config:"block_selectors"` // Block list of selectors for debug logging.

toObserver bool
toIODiscard bool
Expand Down
35 changes: 21 additions & 14 deletions logp/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ func init() {
}

type coreLogger struct {
selectors map[string]struct{} // Set of enabled debug selectors.
rootLogger *zap.Logger // Root logger without any options configured.
globalLogger *zap.Logger // Logger used by legacy global functions (e.g. logp.Info).
logger *Logger // Logger that is the basis for all logp.Loggers.
level zap.AtomicLevel // The minimum level being printed
observedLogs *observer.ObservedLogs // Contains events generated while in observation mode (a testing mode).
selectors map[string]struct{} // Set of enabled debug selectors.
blockSelectors map[string]struct{} // Set of blocked debug selectors.
rootLogger *zap.Logger // Root logger without any options configured.
globalLogger *zap.Logger // Logger used by legacy global functions (e.g. logp.Info).
logger *Logger // Logger that is the basis for all logp.Loggers.
level zap.AtomicLevel // The minimum level being printed
observedLogs *observer.ObservedLogs // Contains events generated while in observation mode (a testing mode).
}

// Configure configures the logp package.
Expand Down Expand Up @@ -97,7 +98,12 @@ func ConfigureWithOutputs(cfg Config, outputs ...zapcore.Core) error {

// Enabled selectors when debug is enabled.
selectors := make(map[string]struct{}, len(cfg.Selectors))
if cfg.Level.Enabled(DebugLevel) && len(cfg.Selectors) > 0 {
blockSelectors := make(map[string]struct{}, len(cfg.BlockSelectors))
if cfg.Level.Enabled(DebugLevel) && (len(cfg.Selectors) > 0 || len(cfg.BlockSelectors) > 0) {
for _, sel := range cfg.BlockSelectors {
blockSelectors[strings.TrimSpace(sel)] = struct{}{}
}

for _, sel := range cfg.Selectors {
selectors[strings.TrimSpace(sel)] = struct{}{}
}
Expand All @@ -115,18 +121,19 @@ func ConfigureWithOutputs(cfg Config, outputs ...zapcore.Core) error {
golog.SetOutput(_defaultGoLog)
}

sink = selectiveWrapper(sink, selectors)
sink = selectiveWrapper(sink, selectors, blockSelectors)
}

sink = newMultiCore(append(outputs, sink)...)
root := zap.New(sink, makeOptions(cfg)...)
storeLogger(&coreLogger{
selectors: selectors,
rootLogger: root,
globalLogger: root.WithOptions(zap.AddCallerSkip(1)),
logger: newLogger(root, ""),
level: level,
observedLogs: observedLogs,
selectors: selectors,
blockSelectors: blockSelectors,
rootLogger: root,
globalLogger: root.WithOptions(zap.AddCallerSkip(1)),
logger: newLogger(root, ""),
level: level,
observedLogs: observedLogs,
})
return nil
}
Expand Down
8 changes: 8 additions & 0 deletions logp/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ func WithSelectors(selectors ...string) Option {
}
}

// WithBlockSelectors specifies what debug selectors are disabled. If no selectors
// are specified, then nothing is blocked
func WithBlockSelectors(blockList ...string) Option {
return func(cfg *Config) {
cfg.BlockSelectors = append(cfg.BlockSelectors, blockList...)
}
}

// ToObserverOutput specifies that the output should be collected in memory so
// that they can be read by an observer by calling ObserverLogs().
func ToObserverOutput() Option {
Expand Down
22 changes: 19 additions & 3 deletions logp/selective.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
type selectiveCore struct {
allSelectors bool
selectors map[string]struct{}
blockList map[string]struct{}
core zapcore.Core
}

Expand All @@ -33,12 +34,24 @@ func HasSelector(selector string) bool {
return found
}

func selectiveWrapper(core zapcore.Core, selectors map[string]struct{}) zapcore.Core {
// IsBlocked returns true if the given selector was explicitly set.
func IsBlocked(selector string) bool {
l := loadLogger()
_, found := l.blockSelectors[selector]
return found
}

func selectiveWrapper(core zapcore.Core, selectors, blockList map[string]struct{}) zapcore.Core {
if len(selectors) == 0 {
return core
}
_, allSelectors := selectors["*"]
return &selectiveCore{selectors: selectors, core: core, allSelectors: allSelectors}
return &selectiveCore{
selectors: selectors,
core: core,
allSelectors: allSelectors,
blockList: blockList,
}
}

// Enabled returns whether a given logging level is enabled when logging a
Expand All @@ -49,7 +62,7 @@ func (c *selectiveCore) Enabled(level zapcore.Level) bool {

// With adds structured context to the Core.
func (c *selectiveCore) With(fields []zapcore.Field) zapcore.Core {
return selectiveWrapper(c.core.With(fields), c.selectors)
return selectiveWrapper(c.core.With(fields), c.selectors, c.blockList)
}

// Check determines whether the supplied Entry should be logged (using the
Expand All @@ -61,6 +74,9 @@ func (c *selectiveCore) With(fields []zapcore.Field) zapcore.Core {
func (c *selectiveCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
if c.Enabled(ent.Level) {
if ent.Level == zapcore.DebugLevel {
if _, blocked := c.blockList[ent.LoggerName]; blocked {
return ce
}
if c.allSelectors {
return ce.AddCore(ent, c)
} else if _, enabled := c.selectors[ent.LoggerName]; enabled {
Expand Down
30 changes: 30 additions & 0 deletions logp/selective_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,33 @@ func TestLoggerSelectors(t *testing.T) {
logs = ObserverLogs().TakeAll()
assert.Len(t, logs, 1)
}

func TestLoggerBlockList(t *testing.T) {
if err := DevelopmentSetup(WithBlockSelectors("tooVerbose", " sensitiveInformation "), ToObserverOutput()); err != nil {
t.Fatal(err)
}

require.True(t, IsBlocked("tooVerbose"))
require.True(t, IsBlocked("sensitiveInformation"))

doesNotLog := NewLogger("tooVerbose")
doesNotLog2 := NewLogger("sensitiveInformation")
willLog := NewLogger("notVerbose")

doesNotLog.Debug("is not logged")
logs := ObserverLogs().TakeAll()
assert.Len(t, logs, 0)

doesNotLog2.Debug("is not logged")
logs = ObserverLogs().TakeAll()
assert.Len(t, logs, 0)

// Selectors only apply to debug level logs.
willLog.Debug("is logged")
logs = ObserverLogs().TakeAll()
assert.Len(t, logs, 1)

willLog.Info("is also logged")
logs = ObserverLogs().TakeAll()
assert.Len(t, logs, 1)
}