golang的zap日志库的简单封装


本文摘自网络,作者mediaufo,侵删。

项目的需要,对zap日志库做了简单的封装,主要是支持如下的功能:

1、支持同步和异步的方式。

2、支持根据不同的日志级别调用不同的writer处理.

具体实现如下

type ZapLogOper interface {
    Debug(msg string, fields ...zap.Field)
    Info(msg string, fields ...zap.Field)
    Warn(msg string, fields ...zap.Field)
    Error(msg string, fields ...zap.Field)
    DPanic(msg string, fields ...zap.Field)
    Panic(msg string, fields ...zap.Field)
    Fatal(msg string, fields ...zap.Field)
}

//同步日志,直接写
type synczaplogger struct {
    zaplog *zap.Logger
}

//异步日志
type asynczaplogger struct {
    zaplog   *zap.Logger
    masyslog *asynclogger
}

type zaplogger struct {
    zaplog   *zap.Logger
    masyslog *asynclogger
}

func setzaplogger(nwriters map[zapcore.Level]zapcore.WriteSyncer) *zap.Logger {
    encoderConfig := zapcore.EncoderConfig{
        TimeKey:        "time",
        MessageKey:     "msg",
        LevelKey:       "level",
        NameKey:        "logger",
        CallerKey:      "caller",
        StacktraceKey:  "stacktrace",
        LineEnding:     zapcore.DefaultLineEnding,
        EncodeLevel:    zapcore.LowercaseLevelEncoder,
        EncodeTime:     zapcore.ISO8601TimeEncoder,
        EncodeDuration: zapcore.StringDurationEncoder,
        EncodeCaller:   zapcore.ShortCallerEncoder,
        //EncodeName: zapcore.FullNameEncoder,
    }
    encoder := zapcore.NewJSONEncoder(encoderConfig)
    lvlenabler := zap.NewAtomicLevel()
    fcore := newfilecore(encoder, nwriters, lvlenabler)
    zaplog := zap.New(fcore) 
    return zaplog
}

func newsynczaplogger(nwriters map[zapcore.Level]zapcore.WriteSyncer) *synczaplogger {

    retlogger := &synczaplogger{}
    retlogger.zaplog = setzaplogger(nwriters)
    return retlogger
}

func newasynczaplogger(nwriters map[zapcore.Level]zapcore.WriteSyncer) *asynczaplogger {
    retlogger := &asynczaplogger{}
    retlogger.zaplog = setzaplogger(nwriters)
    //设置异步的操作
    retlogger.masyslog = newAsyncLogger()
    return retlogger
}

//返回接口
func NewZapLogger(wtMode int, nwriters map[zapcore.Level]zapcore.WriteSyncer) ZapLogOper {
    if wtMode == 0 {
        return newsynczaplogger(nwriters)
    } else {
        return newasynczaplogger(nwriters)
    }
}

func NewAllZapLogger(nwriters map[zapcore.Level]zapcore.WriteSyncer) ZapLogOper {
    retzaplogger := &zaplogger{}
    retzaplogger.zaplog = setzaplogger(nwriters)
    retzaplogger.masyslog = newAsyncLogger()
    return retzaplogger
}

func (log *zaplogger) Debug(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Debug, msg, fields...)
}

func (log *zaplogger) Info(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Info, msg, fields...)
}

func (log *zaplogger) Warn(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Warn, msg, fields...)
}

func (log *zaplogger) Error(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Error, msg, fields...)
}

func (log *zaplogger) DPanic(msg string, fields ...zap.Field) {
    log.zaplog.DPanic(msg, fields...)
}

func (log *zaplogger) Panic(msg string, fields ...zap.Field) {
    log.zaplog.Panic(msg, fields...)
}

func (log *zaplogger) Fatal(msg string, fields ...zap.Field) {
    log.zaplog.Fatal(msg, fields...)
}

//-------
func (log *synczaplogger) Debug(msg string, fields ...zap.Field) {
    log.zaplog.Debug(msg, fields...)
}

func (log *synczaplogger) Info(msg string, fields ...zap.Field) {
    log.zaplog.Info(msg, fields...)
}

func (log *synczaplogger) Warn(msg string, fields ...zap.Field) {
    log.zaplog.Warn(msg, fields...)
}

func (log *synczaplogger) Error(msg string, fields ...zap.Field) {
    log.zaplog.Error(msg, fields...)
}

func (log *synczaplogger) DPanic(msg string, fields ...zap.Field) {
    log.zaplog.DPanic(msg, fields...)
}

func (log *synczaplogger) Panic(msg string, fields ...zap.Field) {
    log.zaplog.Panic(msg, fields...)
}

func (log *synczaplogger) Fatal(msg string, fields ...zap.Field) {
    log.zaplog.Fatal(msg, fields...)
}

func (log *asynczaplogger) Debug(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Debug, msg, fields...)
}

func (log *asynczaplogger) Info(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Info, msg, fields...)
}

func (log *asynczaplogger) Warn(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Warn, msg, fields...)
}

func (log *asynczaplogger) Error(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Error, msg, fields...)
}

func (log *asynczaplogger) DPanic(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.DPanic, msg, fields...)
}

func (log *asynczaplogger) Panic(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Panic, msg, fields...)
}

func (log *asynczaplogger) Fatal(msg string, fields ...zap.Field) {
    log.masyslog.doAsyncLog(log.zaplog.Fatal, msg, fields...)
}

异步的简单实现:
const (
    cst_defmsgsize       = 200
    cst_deffieldnums     = 2
    cst_defmaxlogquenums = 500
)

var _asyncMsgPool = sync.Pool{
    New: func() interface{} {
        return &asyncMsg{msg: make([]byte, 0, cst_defmsgsize),
            fields: make([]zap.Field, 0, cst_deffieldnums)}
    },
}

func newAsyncLogger() *asynclogger {
    mret := &asynclogger{logMsgCh: make(chan *asyncMsg, cst_defmaxlogquenums)}
    mret.start()
    return mret
}

func getAsyncMsg() *asyncMsg {
    return _asyncMsgPool.Get().(*asyncMsg)
}

func putAsynMsg(e *asyncMsg) {
    e.msg = e.msg[:0]
    e.fields = e.fields[:0]
    e.f = nil
    _asyncMsgPool.Put(e)
}

type asyncMsg struct {
    msg    []byte
    fields []zap.Field
    f      func(msg string, fields ...zap.Field)
}

//异步日志
type asynclogger struct {
    //异步队列数据
    logMsgCh chan *asyncMsg
}

func (log *asynclogger) start() {
    go log.doWriteLog()
}

func (log *asynclogger) doWriteLog() {
    for logdata := range log.logMsgCh {
        //可以分池来处理
        logdata.f(string(logdata.msg), logdata.fields...)
        putAsynMsg(logdata)
    }
}

func (log *asynclogger) doAsyncLog(f func(msg string, fields ...zap.Field), msg string, fields ...zap.Field) {
    logdata := getAsyncMsg()
    logdata.msg = append(logdata.msg, msg...)
    logdata.fields = append(logdata.fields, fields...)
    logdata.f = f
    log.logMsgCh <- logdata
}

zap.Core接口的实现
type filecore struct {
    zapcore.LevelEnabler
    enc     zapcore.Encoder
    writers map[zapcore.Level]zapcore.WriteSyncer
}

type FileCore interface {
    zapcore.Core
}

func newfilecore(enc zapcore.Encoder, nwriters map[zapcore.Level]zapcore.WriteSyncer, enab zapcore.LevelEnabler) FileCore {
    retcore := &filecore{
        LevelEnabler: enab,
        enc:          enc,
    }
    retcore.writers = make(map[zapcore.Level]zapcore.WriteSyncer)
    for k, v := range nwriters {
        retcore.writers[k] = v
    }
    return retcore
}

func (c *filecore) With(fields []zapcore.Field) zapcore.Core {
    clone := c.clone()
    for i := range fields {
        fields[i].AddTo(clone.enc)
    }
    return clone
}

func (c *filecore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
    if c.Enabled(ent.Level) {
        return ce.AddCore(ent, c)
    }
    return ce
}

func (c *filecore) Write(ent zapcore.Entry, fields []zapcore.Field) error {
    buf, err := c.enc.EncodeEntry(ent, fields)
    if err != nil {
        return err
    }
        if _,ok:=c.writers[ent.Level];!ok {
             return errors.New("no set level writers")
        }
    _, err = c.writers[ent.Level].Write(buf.Bytes())
    buf.Free()
    if err != nil {
        return err
    }
    if ent.Level > zapcore.ErrorLevel {
        c.writers[ent.Level].Sync()
    }
    return nil
}

func (c *filecore) Sync() error {
    return nil
}

func (c *filecore) clone() *filecore {
    retclone := &filecore{
        LevelEnabler: c.LevelEnabler,
        enc:          c.enc.Clone(),
    }
    retclone.writers = make(map[zapcore.Level]zapcore.WriteSyncer)
    for k, v := range c.writers {
        retclone.writers[k] = v
    }
    return retclone
}


相关阅读 >>

Go命令行参数及标准输入输出介绍

Golang中如何比较字符串是否相等

Go build和Go install的区别

iota在Go中怎么使用

聊聊dubbo-Go-proxy的parammapper

详解Golang cpu的使用设置

聊聊dubbo-Go-proxy的hostfilter

client-Go获取k8s集群内部连接,实现deployment的增删改查

利用 Go/ast 语法树做代码生成

Go1.4 bootstrap 源码安装新版Go

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...