micro-logger-zap/zap.go
Vasiliy Tolstov 87bda48d39 logger: change logger interface
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-08-06 02:42:01 +03:00

251 lines
5.5 KiB
Go

package zap
import (
"context"
"fmt"
"os"
"sync"
"github.com/unistack-org/micro/v3/logger"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
type zaplog struct {
zap *zap.Logger
opts logger.Options
sync.RWMutex
fields map[string]interface{}
}
func (l *zaplog) Init(opts ...logger.Option) error {
var err error
for _, o := range opts {
o(&l.opts)
}
if zlog, ok := l.opts.Context.Value(loggerKey{}).(*zap.Logger); ok {
l.zap = zlog
return nil
}
zapConfig := zap.NewProductionConfig()
if zconfig, ok := l.opts.Context.Value(configKey{}).(zap.Config); ok {
zapConfig = zconfig
}
if zcconfig, ok := l.opts.Context.Value(encoderConfigKey{}).(zapcore.EncoderConfig); ok {
zapConfig.EncoderConfig = zcconfig
}
skip, ok := l.opts.Context.Value(callerSkipKey{}).(int)
if !ok || skip < 1 {
skip = 1
}
// Set log Level if not default
zapConfig.Level = zap.NewAtomicLevel()
if l.opts.Level != logger.InfoLevel {
zapConfig.Level.SetLevel(loggerToZapLevel(l.opts.Level))
}
log, err := zapConfig.Build(zap.AddCallerSkip(skip))
if err != nil {
return err
}
// Adding seed fields if exist
if l.opts.Fields != nil {
data := make([]zap.Field, 0, len(l.opts.Fields)/2)
for i := 0; i < len(l.opts.Fields); i += 2 {
data = append(data, zap.Any(l.opts.Fields[i].(string), l.opts.Fields[i+1]))
}
log = log.With(data...)
}
// Adding namespace
if namespace, ok := l.opts.Context.Value(namespaceKey{}).(string); ok {
log = log.With(zap.Namespace(namespace))
}
// defer log.Sync() ??
l.zap = log
return nil
}
func (l *zaplog) Fields(fields ...interface{}) logger.Logger {
data := make([]zap.Field, 0, len(fields)/2)
for i := 0; i < len(fields); i += 2 {
data = append(data, zap.Any(fields[i].(string), fields[i+1]))
}
zl := &zaplog{
zap: l.zap.With(data...),
opts: l.opts,
}
return zl
}
func (l *zaplog) Errorf(ctx context.Context, msg string, args ...interface{}) {
l.Logf(ctx, logger.ErrorLevel, msg, args...)
}
func (l *zaplog) Debugf(ctx context.Context, msg string, args ...interface{}) {
l.Logf(ctx, logger.DebugLevel, msg, args...)
}
func (l *zaplog) Infof(ctx context.Context, msg string, args ...interface{}) {
l.Logf(ctx, logger.InfoLevel, msg, args...)
}
func (l *zaplog) Fatalf(ctx context.Context, msg string, args ...interface{}) {
l.Logf(ctx, logger.FatalLevel, msg, args...)
os.Exit(1)
}
func (l *zaplog) Tracef(ctx context.Context, msg string, args ...interface{}) {
l.Logf(ctx, logger.TraceLevel, msg, args...)
}
func (l *zaplog) Warnf(ctx context.Context, msg string, args ...interface{}) {
l.Logf(ctx, logger.WarnLevel, msg, args...)
}
func (l *zaplog) Error(ctx context.Context, args ...interface{}) {
l.Log(ctx, logger.ErrorLevel, args...)
}
func (l *zaplog) Debug(ctx context.Context, args ...interface{}) {
l.Log(ctx, logger.DebugLevel, args...)
}
func (l *zaplog) Info(ctx context.Context, args ...interface{}) {
l.Log(ctx, logger.InfoLevel, args...)
}
func (l *zaplog) Fatal(ctx context.Context, args ...interface{}) {
l.Log(ctx, logger.FatalLevel, args...)
os.Exit(1)
}
func (l *zaplog) Trace(ctx context.Context, args ...interface{}) {
l.Log(ctx, logger.TraceLevel, args...)
}
func (l *zaplog) Warn(ctx context.Context, args ...interface{}) {
l.Log(ctx, logger.WarnLevel, args...)
}
func (l *zaplog) Log(ctx context.Context, level logger.Level, args ...interface{}) {
if !l.V(level) {
return
}
l.RLock()
data := make([]zap.Field, 0, len(l.fields))
for k, v := range l.fields {
data = append(data, zap.Any(k, v))
}
l.RUnlock()
msg := fmt.Sprint(args...)
switch loggerToZapLevel(level) {
case zap.DebugLevel:
l.zap.Debug(msg, data...)
case zap.InfoLevel:
l.zap.Info(msg, data...)
case zap.WarnLevel:
l.zap.Warn(msg, data...)
case zap.ErrorLevel:
l.zap.Error(msg, data...)
case zap.FatalLevel:
l.zap.Fatal(msg, data...)
}
}
func (l *zaplog) Logf(ctx context.Context, level logger.Level, format string, args ...interface{}) {
if !l.V(level) {
return
}
l.RLock()
data := make([]zap.Field, 0, len(l.fields))
for k, v := range l.fields {
data = append(data, zap.Any(k, v))
}
l.RUnlock()
msg := fmt.Sprintf(format, args...)
switch loggerToZapLevel(level) {
case zap.DebugLevel:
l.zap.Debug(msg, data...)
case zap.InfoLevel:
l.zap.Info(msg, data...)
case zap.WarnLevel:
l.zap.Warn(msg, data...)
case zap.ErrorLevel:
l.zap.Error(msg, data...)
case zap.FatalLevel:
l.zap.Fatal(msg, data...)
}
}
func (l *zaplog) V(level logger.Level) bool {
return l.zap.Core().Enabled(loggerToZapLevel(level))
}
func (l *zaplog) String() string {
return "zap"
}
func (l *zaplog) Options() logger.Options {
return l.opts
}
// New builds a new logger based on options
func NewLogger(opts ...logger.Option) logger.Logger {
l := &zaplog{opts: logger.NewOptions(opts...)}
return l
}
func loggerToZapLevel(level logger.Level) zapcore.Level {
switch level {
case logger.TraceLevel, logger.DebugLevel:
return zap.DebugLevel
case logger.InfoLevel:
return zap.InfoLevel
case logger.WarnLevel:
return zap.WarnLevel
case logger.ErrorLevel:
return zap.ErrorLevel
case logger.FatalLevel:
return zap.FatalLevel
default:
return zap.InfoLevel
}
}
/*
func zapToLoggerLevel(level zapcore.Level) logger.Level {
switch level {
case zap.DebugLevel:
return logger.DebugLevel
case zap.InfoLevel:
return logger.InfoLevel
case zap.WarnLevel:
return logger.WarnLevel
case zap.ErrorLevel:
return logger.ErrorLevel
case zap.FatalLevel:
return logger.FatalLevel
default:
return logger.InfoLevel
}
}
*/