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

Add support for grpclog.LoggerV2 #881

Merged
merged 13 commits into from Feb 12, 2021
172 changes: 139 additions & 33 deletions zapgrpc/zapgrpc.go
Expand Up @@ -21,7 +21,30 @@
// Package zapgrpc provides a logger that is compatible with grpclog.
package zapgrpc // import "go.uber.org/zap/zapgrpc"

import "go.uber.org/zap"
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

const (
// See https://github.com/grpc/grpc-go/blob/v1.35.0/grpclog/loggerv2.go#L77-L86

ash2k marked this conversation as resolved.
Show resolved Hide resolved
grpcLvlInfo = 0
grpcLvlWarn = 1
grpcLvlError = 2
grpcLvlFatal = 3
)

var (
// grpc2zapLvl maps gRPC log levels to zap log levels.
// See https://pkg.go.dev/go.uber.org/zap@v1.16.0/zapcore#Level
grpc2zapLvl = map[int]zapcore.Level{
ash2k marked this conversation as resolved.
Show resolved Hide resolved
grpcLvlInfo: zapcore.InfoLevel,
grpcLvlWarn: zapcore.WarnLevel,
grpcLvlError: zapcore.ErrorLevel,
grpcLvlFatal: zapcore.FatalLevel,
}
)

// An Option overrides a Logger's default configuration.
type Option interface {
Expand All @@ -36,65 +59,148 @@ func (f optionFunc) apply(log *Logger) {

// WithDebug configures a Logger to print at zap's DebugLevel instead of
// InfoLevel.
// It only affects the Printf, Println and Print methods, which are only used in the gRPC v1 grpclog.Logger API.
// Deprecated: use grpclog.SetLoggerV2() for v2 API.
func WithDebug() Option {
return optionFunc(func(logger *Logger) {
logger.print = (*zap.SugaredLogger).Debug
logger.printf = (*zap.SugaredLogger).Debugf
logger.printToDebug = true
})
}

// NewLogger returns a new Logger.
//
// By default, Loggers print at zap's InfoLevel.
func NewLogger(l *zap.Logger, options ...Option) *Logger {
logger := &Logger{
log: l.Sugar(),
fatal: (*zap.SugaredLogger).Fatal,
fatalf: (*zap.SugaredLogger).Fatalf,
print: (*zap.SugaredLogger).Info,
printf: (*zap.SugaredLogger).Infof,
delegate: l.Sugar(),
printToDebug: false,
fatalToWarn: false,
}
for _, option := range options {
option.apply(logger)
}
return logger
}

// Logger adapts zap's Logger to be compatible with grpclog.Logger.
// Logger adapts zap's Logger to be compatible with grpclog.LoggerV2 and the deprecated grpclog.Logger.
type Logger struct {
log *zap.SugaredLogger
fatal func(*zap.SugaredLogger, ...interface{})
fatalf func(*zap.SugaredLogger, string, ...interface{})
print func(*zap.SugaredLogger, ...interface{})
printf func(*zap.SugaredLogger, string, ...interface{})
delegate *zap.SugaredLogger
printToDebug bool
fatalToWarn bool
}

// Fatal implements grpclog.Logger.
func (l *Logger) Fatal(args ...interface{}) {
l.fatal(l.log, args...)
// Print implements grpclog.Logger.
// Deprecated: use Info().
func (l *Logger) Print(args ...interface{}) {
if l.printToDebug {
l.delegate.Debug(args...)
} else {
l.delegate.Info(args...)
}
}

// Fatalf implements grpclog.Logger.
func (l *Logger) Fatalf(format string, args ...interface{}) {
l.fatalf(l.log, format, args...)
// Printf implements grpclog.Logger.
// Deprecated: use Infof().
func (l *Logger) Printf(format string, args ...interface{}) {
if l.printToDebug {
l.delegate.Debugf(format, args...)
} else {
l.delegate.Infof(format, args...)
}
}

// Println implements grpclog.Logger.
// Deprecated: use Info().
func (l *Logger) Println(args ...interface{}) {
l.Print(addSpaces(args)...)
}

// Info implements grpclog.LoggerV2.
func (l *Logger) Info(args ...interface{}) {
l.delegate.Info(args...)
}

// Infoln implements grpclog.LoggerV2.
func (l *Logger) Infoln(args ...interface{}) {
ash2k marked this conversation as resolved.
Show resolved Hide resolved
l.delegate.Info(addSpaces(args)...)
}

// Infof implements grpclog.LoggerV2.
func (l *Logger) Infof(format string, args ...interface{}) {
l.delegate.Infof(format, args...)
}

// Warning implements grpclog.LoggerV2.
func (l *Logger) Warning(args ...interface{}) {
l.delegate.Warn(args...)
}

// Fatalln implements grpclog.Logger.
// Warningln implements grpclog.LoggerV2.
func (l *Logger) Warningln(args ...interface{}) {
l.delegate.Warn(addSpaces(args)...)
}

// Warningf implements grpclog.LoggerV2.
func (l *Logger) Warningf(format string, args ...interface{}) {
l.delegate.Warnf(format, args...)
}

// Error implements grpclog.LoggerV2.
func (l *Logger) Error(args ...interface{}) {
l.delegate.Error(args...)
}

// Errorln implements grpclog.LoggerV2.
func (l *Logger) Errorln(args ...interface{}) {
l.delegate.Error(addSpaces(args)...)
}

// Errorf implements grpclog.LoggerV2.
func (l *Logger) Errorf(format string, args ...interface{}) {
l.delegate.Errorf(format, args...)
}

// Fatal implements grpclog.LoggerV2.
func (l *Logger) Fatal(args ...interface{}) {
if l.fatalToWarn {
l.delegate.Warn(args...)
} else {
l.delegate.Fatal(args...)
}
}

// Fatalln implements grpclog.LoggerV2.
func (l *Logger) Fatalln(args ...interface{}) {
l.fatal(l.log, args...)
l.Fatal(addSpaces(args)...)
}

// Print implements grpclog.Logger.
func (l *Logger) Print(args ...interface{}) {
l.print(l.log, args...)
// Fatalf implements grpclog.LoggerV2.
func (l *Logger) Fatalf(format string, args ...interface{}) {
if l.fatalToWarn {
l.delegate.Warnf(format, args...)
} else {
l.delegate.Fatalf(format, args...)
}
}

// Printf implements grpclog.Logger.
func (l *Logger) Printf(format string, args ...interface{}) {
l.printf(l.log, format, args...)
// V implements grpclog.LoggerV2.
func (l *Logger) V(level int) bool {
return l.delegate.Desugar().Core().Enabled(grpc2zapLvl[level])
}

// Println implements grpclog.Logger.
func (l *Logger) Println(args ...interface{}) {
l.print(l.log, args...)
// addSpaces always adds spaces between arguments like https://golang.org/pkg/fmt/#Println
func addSpaces(args []interface{}) []interface{} {
ash2k marked this conversation as resolved.
Show resolved Hide resolved
l := len(args)
if l == 0 || l == 1 {
return args
}
res := make([]interface{}, 0, l+l-1)
first := true
for _, arg := range args {
if first {
first = false
res = append(res, arg)
} else {
res = append(res, " ", arg)
}
}
return res
}