Skip to content

Commit

Permalink
Use variadic function to pass parameters instead of Config struct
Browse files Browse the repository at this point in the history
Using function to pass optional params makes the API more consistent
with the rest of go-kit packages.

For go-kit#427
  • Loading branch information
groob committed Feb 9, 2017
1 parent 414b9e6 commit ae92291
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 72 deletions.
30 changes: 12 additions & 18 deletions log/experimental_level/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,41 @@ func BenchmarkNopBaseline(b *testing.B) {
}

func BenchmarkNopDisallowedLevel(b *testing.B) {
benchmarkRunner(b, level.New(log.NewNopLogger(), level.Config{
Allowed: level.AllowInfoAndAbove(),
}))
benchmarkRunner(b, level.New(log.NewNopLogger(),
level.Allowed(level.AllowInfoAndAbove())))
}

func BenchmarkNopAllowedLevel(b *testing.B) {
benchmarkRunner(b, level.New(log.NewNopLogger(), level.Config{
Allowed: level.AllowAll(),
}))
benchmarkRunner(b, level.New(log.NewNopLogger(),
level.Allowed(level.AllowAll())))
}

func BenchmarkJSONBaseline(b *testing.B) {
benchmarkRunner(b, log.NewJSONLogger(ioutil.Discard))
}

func BenchmarkJSONDisallowedLevel(b *testing.B) {
benchmarkRunner(b, level.New(log.NewJSONLogger(ioutil.Discard), level.Config{
Allowed: level.AllowInfoAndAbove(),
}))
benchmarkRunner(b, level.New(log.NewJSONLogger(ioutil.Discard),
level.Allowed(level.AllowInfoAndAbove())))
}

func BenchmarkJSONAllowedLevel(b *testing.B) {
benchmarkRunner(b, level.New(log.NewJSONLogger(ioutil.Discard), level.Config{
Allowed: level.AllowAll(),
}))
benchmarkRunner(b, level.New(log.NewJSONLogger(ioutil.Discard),
level.Allowed(level.AllowAll())))
}

func BenchmarkLogfmtBaseline(b *testing.B) {
benchmarkRunner(b, log.NewLogfmtLogger(ioutil.Discard))
}

func BenchmarkLogfmtDisallowedLevel(b *testing.B) {
benchmarkRunner(b, level.New(log.NewLogfmtLogger(ioutil.Discard), level.Config{
Allowed: level.AllowInfoAndAbove(),
}))
benchmarkRunner(b, level.New(log.NewLogfmtLogger(ioutil.Discard),
level.Allowed(level.AllowInfoAndAbove())))
}

func BenchmarkLogfmtAllowedLevel(b *testing.B) {
benchmarkRunner(b, level.New(log.NewLogfmtLogger(ioutil.Discard), level.Config{
Allowed: level.AllowAll(),
}))
benchmarkRunner(b, level.New(log.NewLogfmtLogger(ioutil.Discard),
level.Allowed(level.AllowAll())))
}

func benchmarkRunner(b *testing.B, logger log.Logger) {
Expand Down
6 changes: 3 additions & 3 deletions log/experimental_level/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
// var logger log.Logger
// logger = log.NewLogfmtLogger(os.Stderr)
// logger = level.New(logger, level.Config{Allowed: level.AllowInfoAndAbove}) // <--
// logger = level.New(logger, level.Allowed(level.AllowInfoAndAbove())) // <--
// logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC)
//
// Then, at the callsites, use one of the level.Debug, Info, Warn, or Error
Expand All @@ -20,8 +20,8 @@
//
// The leveled logger allows precise control over what should happen if a log
// event is emitted without a level key, or if a squelched level is used. Check
// the Config struct for details. And, you can easily use non-default level
// the Option functions for details. And, you can easily use non-default level
// values: create new string constants for whatever you want to change, pass
// them explicitly to the Config struct, and write your own level.Foo-style
// them explicitly to the Allowed Option function, and write your own level.Foo-style
// helper methods.
package level
76 changes: 42 additions & 34 deletions log/experimental_level/level.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,31 @@ func AllowAll() []string {
}

// AllowDebugAndAbove allows all of the four default log levels.
// Its return value may be provided as the Allowed parameter in the Config.
// Its return value may be provided with the Allowed Option.
func AllowDebugAndAbove() []string {
return []string{errorLevelValue, warnLevelValue, infoLevelValue, debugLevelValue}
}

// AllowInfoAndAbove allows the default info, warn, and error log levels.
// Its return value may be provided as the Allowed parameter in the Config.
// Its return value may be provided with the Allowed Option.
func AllowInfoAndAbove() []string {
return []string{errorLevelValue, warnLevelValue, infoLevelValue}
}

// AllowWarnAndAbove allows the default warn and error log levels.
// Its return value may be provided as the Allowed parameter in the Config.
// Its return value may be provided with the Allowed Option.
func AllowWarnAndAbove() []string {
return []string{errorLevelValue, warnLevelValue}
}

// AllowErrorOnly allows only the default error log level.
// Its return value may be provided as the Allowed parameter in the Config.
// Its return value may be provided with the Allowed Option.
func AllowErrorOnly() []string {
return []string{errorLevelValue}
}

// AllowNone allows none of the default log levels.
// Its return value may be provided as the Allowed parameter in the Config.
// Its return value may be provided with the Allowed Option.
func AllowNone() []string {
return []string{}
}
Expand All @@ -67,42 +67,50 @@ func Debug(logger log.Logger) log.Logger {
return log.NewContext(logger).WithPrefix(levelKey, debugLevelValue)
}

// Config parameterizes the leveled logger.
type Config struct {
// Allowed enumerates the accepted log levels. If a log event is encountered
// with a level key set to a value that isn't explicitly allowed, the event
// will be squelched, and ErrNotAllowed returned.
Allowed []string
// New wraps the logger and implements level checking. See the commentary on the
// Option functions for a detailed description of how to configure levels.
func New(next log.Logger, options ...Option) log.Logger {
l := logger{
next: next,
}
for _, option := range options {
option(&l)
}
return &l
}

// ErrNotAllowed is returned to the caller when Log is invoked with a level
// key that hasn't been explicitly allowed. By default, ErrNotAllowed is
// nil; in this case, the log event is squelched with no error.
ErrNotAllowed error
// Allowed enumerates the accepted log levels. If a log event is encountered
// with a level key set to a value that isn't explicitly allowed, the event
// will be squelched, and ErrNotAllowed returned.
func Allowed(allowed []string) Option {
return func(l *logger) { l.allowed = makeSet(allowed) }
}

// SquelchNoLevel will squelch log events with no level key, so that they
// don't proceed through to the wrapped logger. If SquelchNoLevel is set to
// true and a log event is squelched in this way, ErrNoLevel is returned to
// the caller.
SquelchNoLevel bool
// ErrNoLevel is returned to the caller when SquelchNoLevel is true, and Log
// is invoked without a level key. By default, ErrNoLevel is nil; in this
// case, the log event is squelched with no error.
func ErrNotAllowed(err error) Option {
return func(l *logger) { l.errNotAllowed = err }
}

// ErrNoLevel is returned to the caller when SquelchNoLevel is true, and Log
// is invoked without a level key. By default, ErrNoLevel is nil; in this
// case, the log event is squelched with no error.
ErrNoLevel error
// SquelchNoLevel will squelch log events with no level key, so that they
// don't proceed through to the wrapped logger. If SquelchNoLevel is set to
// true and a log event is squelched in this way, ErrNoLevel is returned to
// the caller.
func SquelchNoLevel(squelch bool) Option {
return func(l *logger) { l.squelchNoLevel = squelch }
}

// New wraps the logger and implements level checking. See the commentary on the
// Config object for a detailed description of how to configure levels.
func New(next log.Logger, config Config) log.Logger {
return &logger{
next: next,
allowed: makeSet(config.Allowed),
errNotAllowed: config.ErrNotAllowed,
squelchNoLevel: config.SquelchNoLevel,
errNoLevel: config.ErrNoLevel,
}
// ErrNoLevel is returned to the caller when SquelchNoLevel is true, and Log
// is invoked without a level key. By default, ErrNoLevel is nil; in this
// case, the log event is squelched with no error.
func ErrNoLevel(err error) Option {
return func(l *logger) { l.errNoLevel = err }
}

// Option sets a parameter for the leveled logger.
type Option func(*logger)

type logger struct {
next log.Logger
allowed map[string]struct{}
Expand Down
37 changes: 20 additions & 17 deletions log/experimental_level/level_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestVariousLevels(t *testing.T) {
},
} {
var buf bytes.Buffer
logger := level.New(log.NewJSONLogger(&buf), level.Config{Allowed: testcase.allowed})
logger := level.New(log.NewJSONLogger(&buf), level.Allowed(testcase.allowed))

level.Debug(logger).Log("this is", "debug log")
level.Info(logger).Log("this is", "info log")
Expand All @@ -75,10 +75,11 @@ func TestVariousLevels(t *testing.T) {

func TestErrNotAllowed(t *testing.T) {
myError := errors.New("squelched!")
logger := level.New(log.NewNopLogger(), level.Config{
Allowed: level.AllowWarnAndAbove(),
ErrNotAllowed: myError,
})
opts := []level.Option{
level.Allowed(level.AllowWarnAndAbove()),
level.ErrNotAllowed(myError),
}
logger := level.New(log.NewNopLogger(), opts...)

if want, have := myError, level.Info(logger).Log("foo", "bar"); want != have {
t.Errorf("want %#+v, have %#+v", want, have)
Expand All @@ -93,10 +94,11 @@ func TestErrNoLevel(t *testing.T) {
myError := errors.New("no level specified")

var buf bytes.Buffer
logger := level.New(log.NewJSONLogger(&buf), level.Config{
SquelchNoLevel: true,
ErrNoLevel: myError,
})
opts := []level.Option{
level.SquelchNoLevel(true),
level.ErrNoLevel(myError),
}
logger := level.New(log.NewJSONLogger(&buf), opts...)

if want, have := myError, logger.Log("foo", "bar"); want != have {
t.Errorf("want %v, have %v", want, have)
Expand All @@ -108,10 +110,11 @@ func TestErrNoLevel(t *testing.T) {

func TestAllowNoLevel(t *testing.T) {
var buf bytes.Buffer
logger := level.New(log.NewJSONLogger(&buf), level.Config{
SquelchNoLevel: false,
ErrNoLevel: errors.New("I should never be returned!"),
})
opts := []level.Option{
level.SquelchNoLevel(false),
level.ErrNoLevel(errors.New("I should never be returned!")),
}
logger := level.New(log.NewJSONLogger(&buf), opts...)

if want, have := error(nil), logger.Log("foo", "bar"); want != have {
t.Errorf("want %v, have %v", want, have)
Expand All @@ -128,11 +131,11 @@ func TestLevelContext(t *testing.T) {
// log.DefaultCaller as per normal.
var logger log.Logger
logger = log.NewLogfmtLogger(&buf)
logger = level.New(logger, level.Config{Allowed: level.AllowAll()})
logger = level.New(logger, level.Allowed(level.AllowAll()))
logger = log.NewContext(logger).With("caller", log.DefaultCaller)

level.Info(logger).Log("foo", "bar")
if want, have := `level=info caller=level_test.go:134 foo=bar`, strings.TrimSpace(buf.String()); want != have {
if want, have := `level=info caller=level_test.go:137 foo=bar`, strings.TrimSpace(buf.String()); want != have {
t.Errorf("want %q, have %q", want, have)
}
}
Expand All @@ -145,10 +148,10 @@ func TestContextLevel(t *testing.T) {
var logger log.Logger
logger = log.NewLogfmtLogger(&buf)
logger = log.NewContext(logger).With("caller", log.Caller(5))
logger = level.New(logger, level.Config{Allowed: level.AllowAll()})
logger = level.New(logger, level.Allowed(level.AllowAll()))

level.Info(logger).Log("foo", "bar")
if want, have := `caller=level_test.go:150 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have {
if want, have := `caller=level_test.go:153 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have {
t.Errorf("want %q, have %q", want, have)
}
}

0 comments on commit ae92291

Please sign in to comment.