介紹
zap日志庫是一款高性能的開源日志庫,提供了結構化日志記錄和printf風格的日志記錄
安裝
go get -u go.uber.org/zap
如何在kratos框架中使用
參考官方文檔中描述,為了方便業務自適配不同的 log 接入使用,Logger 只包含了最簡單的 Log 接口。當業務需要在 Kratos 框架內部使用自定義的 log 的時候,只需要簡單實現 Log 方法即可。
日志庫較為公用建議放在kit基礎庫中方便其他微服務引用,可參考Go工程化最佳實踐
實現log接口並配置zap日志庫編碼
package pkg
import (
"fmt"
"github.com/go-kratos/kratos/v2/log"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
)
var _ log.Logger = (*ZapLogger)(nil)
type ZapLogger struct {
log *zap.Logger
Sync func() error
}
// Logger 配置zap日志,將zap日志庫引入
func Logger() log.Logger {
//配置zap日志庫的編碼器
encoder := zapcore.EncoderConfig{
TimeKey: "time",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "msg",
StacktraceKey: "stack",
EncodeTime: zapcore.ISO8601TimeEncoder,
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.FullCallerEncoder,
}
return NewZapLogger(
encoder,
zap.NewAtomicLevelAt(zapcore.DebugLevel),
zap.AddStacktrace(
zap.NewAtomicLevelAt(zapcore.ErrorLevel)),
zap.AddCaller(),
zap.AddCallerSkip(2),
zap.Development(),
)
}
// 日志自動切割,采用 lumberjack 實現的
func getLogWriter() zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: "../../zap.log", //指定日志存儲位置
MaxSize: 10, //日志的最大大小(M)
MaxBackups: 5, //日志的最大保存數量
MaxAge: 30, //日志文件存儲最大天數
Compress: false, //是否執行壓縮
}
return zapcore.AddSync(lumberJackLogger)
}
// NewZapLogger return a zap logger.
func NewZapLogger(encoder zapcore.EncoderConfig, level zap.AtomicLevel, opts ...zap.Option) *ZapLogger {
//日志切割
writeSyncer := getLogWriter()
//設置日志級別
level.SetLevel(zap.InfoLevel)
var core zapcore.Core
//開發模式下打印到標准輸出
// --根據配置文件判斷輸出到控制台還是日志文件--
if conf.GetConfig().GetString("project.mode") == "dev" {
core = zapcore.NewCore(
zapcore.NewConsoleEncoder(encoder), // 編碼器配置
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout)), // 打印到控制台
level, // 日志級別
)
} else {
core = zapcore.NewCore(
zapcore.NewJSONEncoder(encoder), // 編碼器配置
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(writeSyncer)), // 打印到控制台和文件
level, // 日志級別
)
}
zapLogger := zap.New(core, opts...)
return &ZapLogger{log: zapLogger, Sync: zapLogger.Sync}
}
// Log 實現log接口
func (l *ZapLogger) Log(level log.Level, keyvals ...interface{}) error {
if len(keyvals) == 0 || len(keyvals)%2 != 0 {
l.log.Warn(fmt.Sprint("Keyvalues must appear in pairs: ", keyvals))
return nil
}
var data []zap.Field
for i := 0; i < len(keyvals); i += 2 {
data = append(data, zap.Any(fmt.Sprint(keyvals[i]), keyvals[i+1]))
}
switch level {
case log.LevelDebug:
l.log.Debug("", data...)
case log.LevelInfo:
l.log.Info("", data...)
case log.LevelWarn:
l.log.Warn("", data...)
case log.LevelError:
l.log.Error("", data...)
case log.LevelFatal:
l.log.Fatal("", data...)
}
return nil
}
替換為zap日志庫
在main函數中將元日志替換為zap日志
app, cleanup, err := initApp(bc.Server, bc.Data, zaoLog.Logger())
添加日志中間件
在 grpc.ServerOption和http.ServerOption 中引入 logging.Server(), 則會在每次收到 gRPC 請求的時候打印詳細請求信息。
var opts = []grpc.ServerOption{
grpc.Middleware(
recovery.Recovery(),
logging.Server(logger),//日志中間件
),
}
//=======================================
var opts = []http.ServerOption{
http.Middleware(
recovery.Recovery(),
logging.Server(logger),//日志中間件
),
}
在 grpc.WithMiddleware和http.WithMiddleware 中引入 logging.Client(), 則會在每次發起 grpc 請求的時候打印詳細請求信息。
logger := log.DefaultLogger
conn, err := transgrpc.DialInsecure(
context.Background(),
grpc.WithEndpoint("127.0.0.1:9000"),
grpc.WithMiddleware(
logging.Client(logger),
),
)
//=======================================
logger := log.DefaultLogger
conn, err := http.NewClient(
context.Background(),
http.WithMiddleware(
logging.Client(logger),
),
http.WithEndpoint("127.0.0.1:8000"),
)
如有錯誤請留言反饋