github.com/status-im/status-go@v1.1.0/logutils/zap_adapter.go (about)

     1  package logutils
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"time"
     7  
     8  	"go.uber.org/zap"
     9  	"go.uber.org/zap/zapcore"
    10  
    11  	"github.com/ethereum/go-ethereum/log"
    12  
    13  	"github.com/status-im/status-go/protocol/zaputil"
    14  )
    15  
    16  type gethLoggerCore struct {
    17  	zapcore.LevelEnabler
    18  	fields []zapcore.Field
    19  	logger log.Logger
    20  }
    21  
    22  func (c gethLoggerCore) With(fields []zapcore.Field) zapcore.Core {
    23  	clone := c.clone()
    24  	clone.fields = append(clone.fields, fields...)
    25  	return clone
    26  }
    27  
    28  func (c gethLoggerCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
    29  	if c.Enabled(ent.Level) {
    30  		return ce.AddCore(ent, c)
    31  	}
    32  	return ce
    33  }
    34  func (c gethLoggerCore) Write(ent zapcore.Entry, fields []zapcore.Field) error {
    35  	fields = append(c.fields[:], fields...)
    36  
    37  	var args []interface{}
    38  	for _, f := range fields {
    39  		switch f.Type {
    40  		case zapcore.ArrayMarshalerType,
    41  			zapcore.ObjectMarshalerType,
    42  			zapcore.BinaryType,
    43  			zapcore.ByteStringType,
    44  			zapcore.Complex128Type,
    45  			zapcore.ReflectType,
    46  			zapcore.StringerType,
    47  			zapcore.ErrorType:
    48  			args = append(args, f.Key, f.Interface)
    49  		case zapcore.BoolType:
    50  			args = append(args, f.Key, f.Integer == 1)
    51  		case zapcore.DurationType:
    52  			args = append(args, f.Key, time.Duration(f.Integer))
    53  		case zapcore.Float64Type:
    54  			args = append(args, f.Key, math.Float64frombits(uint64(f.Integer)))
    55  		case zapcore.Float32Type:
    56  			args = append(args, f.Key, math.Float32frombits(uint32(f.Integer)))
    57  		case zapcore.Int64Type,
    58  			zapcore.Int32Type,
    59  			zapcore.Int16Type,
    60  			zapcore.Int8Type,
    61  			zapcore.Uint64Type,
    62  			zapcore.Uint32Type,
    63  			zapcore.Uint16Type,
    64  			zapcore.Uint8Type:
    65  			args = append(args, f.Key, f.Integer)
    66  		case zapcore.UintptrType:
    67  			args = append(args, f.Key, uintptr(f.Integer))
    68  		case zapcore.StringType:
    69  			args = append(args, f.Key, f.String)
    70  		case zapcore.TimeType:
    71  			if f.Interface != nil {
    72  				args = append(args, f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location)))
    73  			} else {
    74  				// Fall back to UTC if location is nil.
    75  				args = append(args, f.Key, time.Unix(0, f.Integer))
    76  			}
    77  		case zapcore.NamespaceType:
    78  			args = append(args, "namespace", f.Key)
    79  		case zapcore.SkipType:
    80  			break
    81  		default:
    82  			panic(fmt.Sprintf("unknown field type: %v", f))
    83  		}
    84  	}
    85  
    86  	// set callDepth to 3 for `Output` to skip the calls to zap.Logger
    87  	// and get the correct caller in the log
    88  	callDepth := 3
    89  	switch ent.Level {
    90  	case zapcore.DebugLevel:
    91  		c.logger.Output(ent.Message, log.LvlDebug, callDepth, args...)
    92  	case zapcore.InfoLevel:
    93  		c.logger.Output(ent.Message, log.LvlInfo, callDepth, args...)
    94  	case zapcore.WarnLevel:
    95  		c.logger.Output(ent.Message, log.LvlWarn, callDepth, args...)
    96  	case zapcore.ErrorLevel:
    97  		c.logger.Output(ent.Message, log.LvlError, callDepth, args...)
    98  	case zapcore.DPanicLevel, zapcore.PanicLevel, zapcore.FatalLevel:
    99  		c.logger.Output(ent.Message, log.LvlCrit, callDepth, args...)
   100  	}
   101  
   102  	return nil
   103  }
   104  
   105  func (gethLoggerCore) Sync() error {
   106  	return nil
   107  }
   108  
   109  func (c *gethLoggerCore) clone() *gethLoggerCore {
   110  	return &gethLoggerCore{
   111  		LevelEnabler: c.LevelEnabler,
   112  		fields:       c.fields,
   113  		logger:       c.logger,
   114  	}
   115  }
   116  
   117  // NewZapAdapter returns a new zapcore.Core interface which forwards logs to log.Logger.
   118  func NewZapAdapter(logger log.Logger, enab zapcore.LevelEnabler) zapcore.Core {
   119  	return &gethLoggerCore{
   120  		LevelEnabler: enab,
   121  		logger:       logger,
   122  	}
   123  }
   124  
   125  // NewZapLoggerWithAdapter returns a logger forwarding all logs with level info and above.
   126  func NewZapLoggerWithAdapter(logger log.Logger) (*zap.Logger, error) {
   127  	if err := zaputil.RegisterJSONHexEncoder(); err != nil {
   128  		panic(err)
   129  	}
   130  
   131  	cfg := zap.Config{
   132  		Level:            zap.NewAtomicLevelAt(zapcore.DebugLevel),
   133  		Development:      false,
   134  		Sampling:         nil,
   135  		Encoding:         "json-hex",
   136  		EncoderConfig:    zap.NewProductionEncoderConfig(),
   137  		OutputPaths:      []string{"stderr"},
   138  		ErrorOutputPaths: []string{"stderr"},
   139  	}
   140  	adapter := zap.WrapCore(
   141  		func(zapcore.Core) zapcore.Core {
   142  			return NewZapAdapter(logger, cfg.Level)
   143  		},
   144  	)
   145  	log.PrintOrigins(true)
   146  	return cfg.Build(adapter)
   147  }