| // Copyright (c) 2016 Uber Technologies, Inc. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| |
| // Package zapgrpc provides a logger that is compatible with grpclog. |
| package zapgrpc // import "go.uber.org/zap/zapgrpc" |
| |
| import ( |
| "fmt" |
| |
| "go.uber.org/zap" |
| "go.uber.org/zap/zapcore" |
| ) |
| |
| // See https://github.com/grpc/grpc-go/blob/v1.35.0/grpclog/loggerv2.go#L77-L86 |
| const ( |
| grpcLvlInfo int = iota |
| grpcLvlWarn |
| grpcLvlError |
| grpcLvlFatal |
| ) |
| |
| // _grpcToZapLevel maps gRPC log levels to zap log levels. |
| // See https://pkg.go.dev/go.uber.org/zap@v1.16.0/zapcore#Level |
| var _grpcToZapLevel = map[int]zapcore.Level{ |
| grpcLvlInfo: zapcore.InfoLevel, |
| grpcLvlWarn: zapcore.WarnLevel, |
| grpcLvlError: zapcore.ErrorLevel, |
| grpcLvlFatal: zapcore.FatalLevel, |
| } |
| |
| // An Option overrides a Logger's default configuration. |
| type Option interface { |
| apply(*Logger) |
| } |
| |
| type optionFunc func(*Logger) |
| |
| func (f optionFunc) apply(log *Logger) { |
| f(log) |
| } |
| |
| // 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 = &printer{ |
| enab: logger.levelEnabler, |
| level: zapcore.DebugLevel, |
| print: logger.delegate.Debug, |
| printf: logger.delegate.Debugf, |
| } |
| }) |
| } |
| |
| // withWarn redirects the fatal level to the warn level, which makes testing |
| // easier. This is intentionally unexported. |
| func withWarn() Option { |
| return optionFunc(func(logger *Logger) { |
| logger.fatal = &printer{ |
| enab: logger.levelEnabler, |
| level: zapcore.WarnLevel, |
| print: logger.delegate.Warn, |
| printf: logger.delegate.Warnf, |
| } |
| }) |
| } |
| |
| // NewLogger returns a new Logger. |
| func NewLogger(l *zap.Logger, options ...Option) *Logger { |
| logger := &Logger{ |
| delegate: l.Sugar(), |
| levelEnabler: l.Core(), |
| } |
| logger.print = &printer{ |
| enab: logger.levelEnabler, |
| level: zapcore.InfoLevel, |
| print: logger.delegate.Info, |
| printf: logger.delegate.Infof, |
| } |
| logger.fatal = &printer{ |
| enab: logger.levelEnabler, |
| level: zapcore.FatalLevel, |
| print: logger.delegate.Fatal, |
| printf: logger.delegate.Fatalf, |
| } |
| for _, option := range options { |
| option.apply(logger) |
| } |
| return logger |
| } |
| |
| // printer implements Print, Printf, and Println operations for a Zap level. |
| // |
| // We use it to customize Debug vs Info, and Warn vs Fatal for Print and Fatal |
| // respectively. |
| type printer struct { |
| enab zapcore.LevelEnabler |
| level zapcore.Level |
| print func(...interface{}) |
| printf func(string, ...interface{}) |
| } |
| |
| func (v *printer) Print(args ...interface{}) { |
| v.print(args...) |
| } |
| |
| func (v *printer) Printf(format string, args ...interface{}) { |
| v.printf(format, args...) |
| } |
| |
| func (v *printer) Println(args ...interface{}) { |
| if v.enab.Enabled(v.level) { |
| v.print(sprintln(args)) |
| } |
| } |
| |
| // Logger adapts zap's Logger to be compatible with grpclog.LoggerV2 and the deprecated grpclog.Logger. |
| type Logger struct { |
| delegate *zap.SugaredLogger |
| levelEnabler zapcore.LevelEnabler |
| print *printer |
| fatal *printer |
| // printToDebug bool |
| // fatalToWarn bool |
| } |
| |
| // Print implements grpclog.Logger. |
| // |
| // Deprecated: use [Logger.Info]. |
| func (l *Logger) Print(args ...interface{}) { |
| l.print.Print(args...) |
| } |
| |
| // Printf implements grpclog.Logger. |
| // |
| // Deprecated: use [Logger.Infof]. |
| func (l *Logger) Printf(format string, args ...interface{}) { |
| l.print.Printf(format, args...) |
| } |
| |
| // Println implements grpclog.Logger. |
| // |
| // Deprecated: use [Logger.Info]. |
| func (l *Logger) Println(args ...interface{}) { |
| l.print.Println(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{}) { |
| if l.levelEnabler.Enabled(zapcore.InfoLevel) { |
| l.delegate.Info(sprintln(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...) |
| } |
| |
| // Warningln implements grpclog.LoggerV2. |
| func (l *Logger) Warningln(args ...interface{}) { |
| if l.levelEnabler.Enabled(zapcore.WarnLevel) { |
| l.delegate.Warn(sprintln(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{}) { |
| if l.levelEnabler.Enabled(zapcore.ErrorLevel) { |
| l.delegate.Error(sprintln(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{}) { |
| l.fatal.Print(args...) |
| } |
| |
| // Fatalln implements grpclog.LoggerV2. |
| func (l *Logger) Fatalln(args ...interface{}) { |
| l.fatal.Println(args...) |
| } |
| |
| // Fatalf implements grpclog.LoggerV2. |
| func (l *Logger) Fatalf(format string, args ...interface{}) { |
| l.fatal.Printf(format, args...) |
| } |
| |
| // V implements grpclog.LoggerV2. |
| func (l *Logger) V(level int) bool { |
| return l.levelEnabler.Enabled(_grpcToZapLevel[level]) |
| } |
| |
| func sprintln(args []interface{}) string { |
| s := fmt.Sprintln(args...) |
| // Drop the new line character added by Sprintln |
| return s[:len(s)-1] |
| } |