From aba719e4c2db172afe8f36d6273ff542b8dede61 Mon Sep 17 00:00:00 2001 From: Gyuho Lee Date: Fri, 2 Feb 2018 12:01:53 -0800 Subject: [PATCH] pkg/logger: add "Lvl" to "Logger" Signed-off-by: Gyuho Lee --- pkg/logger/discard.go | 9 +++-- pkg/logger/logger.go | 47 ++++++++++++++++++++++-- pkg/logger/logger_test.go | 53 +++++++++++++++++++++++++++ pkg/logger/package_logger.go | 20 ++++++++--- pkg/logger/package_logger_test.go | 59 +++++++++++++++++++++++++++++++ 5 files changed, 178 insertions(+), 10 deletions(-) create mode 100644 pkg/logger/logger_test.go create mode 100644 pkg/logger/package_logger_test.go diff --git a/pkg/logger/discard.go b/pkg/logger/discard.go index bda2fbc91..0ac32462e 100644 --- a/pkg/logger/discard.go +++ b/pkg/logger/discard.go @@ -14,9 +14,13 @@ package logger -import "log" +import ( + "log" -// assert that Logger satisfies grpclog.LoggerV2 + "google.golang.org/grpc/grpclog" +) + +// assert that "discardLogger" satisfy "Logger" interface var _ Logger = &discardLogger{} // NewDiscardLogger returns a new Logger that discards everything except "fatal". @@ -39,3 +43,4 @@ func (l *discardLogger) Fatalf(format string, args ...interface{}) { log.Fatal func (l *discardLogger) V(lvl int) bool { return false } +func (l *discardLogger) Lvl(lvl int) grpclog.LoggerV2 { return l } diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 903969339..1256cec64 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -17,6 +17,47 @@ package logger import "google.golang.org/grpc/grpclog" // Logger defines logging interface. -// TODO: add "Lvl(lvl int)" for clientv3 loggers. -// TODO: make this settable with "Set" method. -type Logger grpclog.LoggerV2 +type Logger interface { + grpclog.LoggerV2 + + // Lvl returns logger if logger's verbosity level >= "lvl". + // Otherwise, logger that discards everything. + Lvl(lvl int) grpclog.LoggerV2 +} + +// assert that "defaultLogger" satisfy "Logger" interface +var _ Logger = &defaultLogger{} + +// New wraps "grpclog.LoggerV2" that implements "Logger" interface. +// +// For example: +// +// var defaultLogger Logger +// g := grpclog.NewLoggerV2WithVerbosity(os.Stderr, os.Stderr, os.Stderr, 4) +// defaultLogger = New(g) +// +func New(g grpclog.LoggerV2) Logger { return &defaultLogger{g: g} } + +type defaultLogger struct { + g grpclog.LoggerV2 +} + +func (l *defaultLogger) Info(args ...interface{}) { l.g.Info(args...) } +func (l *defaultLogger) Infoln(args ...interface{}) { l.g.Info(args...) } +func (l *defaultLogger) Infof(format string, args ...interface{}) { l.g.Infof(format, args...) } +func (l *defaultLogger) Warning(args ...interface{}) { l.g.Warning(args...) } +func (l *defaultLogger) Warningln(args ...interface{}) { l.g.Warning(args...) } +func (l *defaultLogger) Warningf(format string, args ...interface{}) { l.g.Warningf(format, args...) } +func (l *defaultLogger) Error(args ...interface{}) { l.g.Error(args...) } +func (l *defaultLogger) Errorln(args ...interface{}) { l.g.Error(args...) } +func (l *defaultLogger) Errorf(format string, args ...interface{}) { l.g.Errorf(format, args...) } +func (l *defaultLogger) Fatal(args ...interface{}) { l.g.Fatal(args...) } +func (l *defaultLogger) Fatalln(args ...interface{}) { l.g.Fatal(args...) } +func (l *defaultLogger) Fatalf(format string, args ...interface{}) { l.g.Fatalf(format, args...) } +func (l *defaultLogger) V(lvl int) bool { return l.g.V(lvl) } +func (l *defaultLogger) Lvl(lvl int) grpclog.LoggerV2 { + if l.g.V(lvl) { + return l + } + return &discardLogger{} +} diff --git a/pkg/logger/logger_test.go b/pkg/logger/logger_test.go new file mode 100644 index 000000000..b50eeb2a8 --- /dev/null +++ b/pkg/logger/logger_test.go @@ -0,0 +1,53 @@ +// Copyright 2017 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logger_test + +import ( + "bytes" + "io/ioutil" + "strings" + "testing" + + "github.com/coreos/etcd/pkg/logger" + + "google.golang.org/grpc/grpclog" +) + +func TestLogger(t *testing.T) { + buf := new(bytes.Buffer) + + l := logger.New(grpclog.NewLoggerV2WithVerbosity(buf, buf, buf, 10)) + l.Infof("hello world!") + if !strings.Contains(buf.String(), "hello world!") { + t.Fatalf("expected 'hello world!', got %q", buf.String()) + } + buf.Reset() + + l.Lvl(10).Infof("Level 10") + l.Lvl(30).Infof("Level 30") + if !strings.Contains(buf.String(), "Level 10") { + t.Fatalf("expected 'Level 10', got %q", buf.String()) + } + if strings.Contains(buf.String(), "Level 30") { + t.Fatalf("unexpected 'Level 30', got %q", buf.String()) + } + buf.Reset() + + l = logger.New(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, ioutil.Discard)) + l.Infof("ignore this") + if len(buf.Bytes()) > 0 { + t.Fatalf("unexpected logs %q", buf.String()) + } +} diff --git a/pkg/logger/package_logger.go b/pkg/logger/package_logger.go index 8d645f499..576f31d2f 100644 --- a/pkg/logger/package_logger.go +++ b/pkg/logger/package_logger.go @@ -14,9 +14,12 @@ package logger -import "github.com/coreos/pkg/capnslog" +import ( + "github.com/coreos/pkg/capnslog" + "google.golang.org/grpc/grpclog" +) -// assert that Logger satisfies grpclog.LoggerV2 +// assert that "packageLogger" satisfy "Logger" interface var _ Logger = &packageLogger{} // NewPackageLogger wraps "*capnslog.PackageLogger" that implements "Logger" interface. @@ -24,10 +27,11 @@ var _ Logger = &packageLogger{} // For example: // // var defaultLogger Logger -// plog := capnslog.NewPackageLogger("github.com/coreos/etcd", "snapshot") -// defaultLogger = NewPackageLogger(plog) +// defaultLogger = NewPackageLogger("github.com/coreos/etcd", "snapshot") // -func NewPackageLogger(p *capnslog.PackageLogger) Logger { return &packageLogger{p: p} } +func NewPackageLogger(repo, pkg string) Logger { + return &packageLogger{p: capnslog.NewPackageLogger(repo, pkg)} +} type packageLogger struct { p *capnslog.PackageLogger @@ -48,3 +52,9 @@ func (l *packageLogger) Fatalf(format string, args ...interface{}) { l.p.Fatal func (l *packageLogger) V(lvl int) bool { return l.p.LevelAt(capnslog.LogLevel(lvl)) } +func (l *packageLogger) Lvl(lvl int) grpclog.LoggerV2 { + if l.p.LevelAt(capnslog.LogLevel(lvl)) { + return l + } + return &discardLogger{} +} diff --git a/pkg/logger/package_logger_test.go b/pkg/logger/package_logger_test.go new file mode 100644 index 000000000..8205ec9f5 --- /dev/null +++ b/pkg/logger/package_logger_test.go @@ -0,0 +1,59 @@ +// Copyright 2017 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logger_test + +import ( + "bytes" + "io/ioutil" + "strings" + "testing" + + "github.com/coreos/pkg/capnslog" + + "github.com/coreos/etcd/pkg/logger" +) + +func TestPackageLogger(t *testing.T) { + buf := new(bytes.Buffer) + capnslog.SetFormatter(capnslog.NewDefaultFormatter(buf)) + + l := logger.NewPackageLogger("github.com/coreos/etcd", "logger") + + r := capnslog.MustRepoLogger("github.com/coreos/etcd") + r.SetLogLevel(map[string]capnslog.LogLevel{"logger": capnslog.INFO}) + + l.Infof("hello world!") + if !strings.Contains(buf.String(), "hello world!") { + t.Fatalf("expected 'hello world!', got %q", buf.String()) + } + buf.Reset() + + // capnslog.INFO is 3 + l.Lvl(2).Infof("Level 2") + l.Lvl(5).Infof("Level 5") + if !strings.Contains(buf.String(), "Level 2") { + t.Fatalf("expected 'Level 2', got %q", buf.String()) + } + if strings.Contains(buf.String(), "Level 5") { + t.Fatalf("unexpected 'Level 5', got %q", buf.String()) + } + buf.Reset() + + capnslog.SetFormatter(capnslog.NewDefaultFormatter(ioutil.Discard)) + l.Infof("ignore this") + if len(buf.Bytes()) > 0 { + t.Fatalf("unexpected logs %q", buf.String()) + } +}