runtime/tchannel_logger.go (73 lines of code) (raw):
// Copyright (c) 2023 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 zanzibar
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/uber/tchannel-go"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// NewTChannelLogger creates a TChannel logger given a zap logger
func NewTChannelLogger(logger *zap.Logger) tchannel.Logger {
return TChannelLogger{logger: logger}
}
// TChannelLogger warps a zap logger to be used for TChannel internal logging
type TChannelLogger struct {
logger *zap.Logger
}
// Enabled returns whether the given level is enabled.
func (l TChannelLogger) Enabled(tlevel tchannel.LogLevel) bool {
var zlevel zapcore.Level
// Log level mapping:
//
// TChannel Zap
// all 0 n/a
// debug 1 -1
// info 2 0
// warn 3 1
// error 4 2
// dpanic n/a 3
// panic n/a 4
// fatal 5 5
//
switch tlevel {
case tchannel.LogLevelAll:
// zap does not have a log all level, zap minimum log level is debug
return false
case tchannel.LogLevelFatal:
zlevel = zapcore.Level(tlevel)
default:
zlevel = zapcore.Level(tlevel - 2)
}
return l.logger.Check(zlevel, "") != nil
}
// Fatal logs a message, then exits with os.Exit(1).
func (l TChannelLogger) Fatal(msg string) {
l.logger.Fatal(msg)
}
// Error logs a message at error priority.
func (l TChannelLogger) Error(msg string) {
l.logger.Error(msg)
}
// Warn logs a message at warning priority.
func (l TChannelLogger) Warn(msg string) {
l.logger.Warn(msg)
}
// Infof logs a message at info priority.
func (l TChannelLogger) Infof(msg string, args ...interface{}) {
l.logger.Info(fmt.Sprintf(msg, args...))
}
// Info logs a message at info priority.
func (l TChannelLogger) Info(msg string) {
l.logger.Info(msg)
}
// Debugf logs a message at debug priority.
func (l TChannelLogger) Debugf(msg string, args ...interface{}) {
l.logger.Debug(fmt.Sprintf(msg, args...))
}
// Debug logs a message at debug priority.
func (l TChannelLogger) Debug(msg string) {
l.logger.Debug(msg)
}
// Fields returns the fields that this logger contains.
func (l TChannelLogger) Fields() tchannel.LogFields {
// zap logger does not expose the fields
// zap.With writes the field to underlying buffer
// fortunately TChannel-go does not call this method except in tests
return nil
}
// WithFields returns a logger with the current logger's fields and fields.
func (l TChannelLogger) WithFields(fields ...tchannel.LogField) tchannel.Logger {
zfields := []zapcore.Field{}
for _, tf := range fields {
zf := zap.Any(tf.Key, tf.Value)
zfields = append(zfields, zf)
}
return TChannelLogger{logger: l.logger.With(zfields...)}
}
// LogErrorWarnTimeout logs warnings for timeout errors, otherwise logs errors
// TODO: We want to improve the classification of errors, similar to:
// https://github.com/uber/tchannel-node/blob/master/errors.js#L907-L930
//
// Deprecated: use proper level to log instead
func LogErrorWarnTimeout(logger *zap.Logger, err error, msg string) {
if isTimeout(err) {
logger.Warn(msg, zap.Error(err))
} else {
logger.Error(msg, zap.Error(err))
}
}
// isTimeout return true if error caused by timeout or context cancel
// used by LogErrorWarnTimeout
func isTimeout(err error) bool {
cause := errors.Cause(err)
return cause == context.Canceled ||
cause == context.DeadlineExceeded ||
tchannel.GetSystemErrorCode(
errors.Cause(err)) == tchannel.ErrCodeTimeout
}