216 lines
4.3 KiB
Go
216 lines
4.3 KiB
Go
package zap
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
|
|
"github.com/micro/go-micro/v2/logger"
|
|
)
|
|
|
|
type zaplog struct {
|
|
cfg zap.Config
|
|
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)
|
|
}
|
|
|
|
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 := []zap.Field{}
|
|
for k, v := range l.opts.Fields {
|
|
data = append(data, zap.Any(k, v))
|
|
}
|
|
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.cfg = zapConfig
|
|
l.zap = log
|
|
l.fields = make(map[string]interface{})
|
|
|
|
return nil
|
|
}
|
|
|
|
func (l *zaplog) Fields(fields map[string]interface{}) logger.Logger {
|
|
l.Lock()
|
|
nfields := make(map[string]interface{}, len(l.fields))
|
|
for k, v := range l.fields {
|
|
nfields[k] = v
|
|
}
|
|
l.Unlock()
|
|
for k, v := range fields {
|
|
nfields[k] = v
|
|
}
|
|
|
|
data := make([]zap.Field, 0, len(nfields))
|
|
for k, v := range fields {
|
|
data = append(data, zap.Any(k, v))
|
|
}
|
|
|
|
zl := &zaplog{
|
|
cfg: l.cfg,
|
|
zap: l.zap.With(data...),
|
|
opts: l.opts,
|
|
fields: make(map[string]interface{}),
|
|
}
|
|
|
|
return zl
|
|
}
|
|
|
|
func (l *zaplog) Error(err error) logger.Logger {
|
|
return l.Fields(map[string]interface{}{"error": err})
|
|
}
|
|
|
|
func (l *zaplog) Log(level logger.Level, args ...interface{}) {
|
|
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()
|
|
|
|
lvl := loggerToZapLevel(level)
|
|
msg := fmt.Sprint(args...)
|
|
switch lvl {
|
|
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(level logger.Level, format string, args ...interface{}) {
|
|
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()
|
|
|
|
lvl := loggerToZapLevel(level)
|
|
msg := fmt.Sprintf(format, args...)
|
|
switch lvl {
|
|
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) 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, error) {
|
|
// Default options
|
|
options := logger.Options{
|
|
Level: logger.InfoLevel,
|
|
Fields: make(map[string]interface{}),
|
|
Out: os.Stderr,
|
|
Context: context.Background(),
|
|
}
|
|
|
|
l := &zaplog{opts: options}
|
|
if err := l.Init(opts...); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return l, nil
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|