一.如何在kratos框架中使用
参考官方文档中描述,为了方便业务自适配不同的 log 接入使用,Logger 只包含了最简单的 Log 接口。当业务需要在 Kratos 框架内部使用自定义的 log的时候,只需要简单实现方法即可。日志库较为公用建议放在kit基础库中方便其他微服务引用。在kratos日志中,很多时候是输出到控制台的,但是实践中更多的是为了打印到文本中。
1.实现log接口并配置zap日志库编码
package logimport ("fmt""time""github.com/go-kratos/kratos/v2/log""github.com/natefinch/lumberjack""go.uber.org/zap""go.uber.org/zap/zapcore"
)var _ log.Logger = (*ZapLogger)(nil)// ZapLogger is a logger impl.
type ZapLogger struct {log *zap.LoggerSync func() error
}// NewZapLogger return a zap logger.
func NewZapLogger(encoder zapcore.EncoderConfig, level zap.AtomicLevel, opts ...zap.Option) *ZapLogger {dateTime := time.Now().Format("2006_01_02_15_04_05")lumberJackLogger := &lumberjack.Logger{Filename: "./log/" + dateTime + "test.log",MaxSize: 1, //修改文本大小,默认为1 MBMaxBackups: 5,MaxAge: 30,Compress: false,}core := zapcore.NewCore(zapcore.NewConsoleEncoder(encoder),zapcore.NewMultiWriteSyncer(//zapcore.AddSync(os.Stdout), //输出到控制台上zapcore.AddSync(lumberJackLogger), //输出到文本中), level)zapLogger := zap.New(core, opts...)return &ZapLogger{log: zapLogger, Sync: zapLogger.Sync}
}// Log Implementation of logger interface.
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}// Zap.Field is used when keyvals pairs appearvar data []zap.Fieldfor i := 0; i < len(keyvals); i += 2 {data = append(data, zap.Any(fmt.Sprint(keyvals[i]), fmt.Sprint(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...)}return nil
}
二.替换为zap日志库
package mainimport ("flag""os""blog/internal/conf"zaplog "blog/cmd/blog/zap""time""github.com/go-kratos/kratos/v2""github.com/go-kratos/kratos/v2/config""github.com/go-kratos/kratos/v2/config/file""github.com/go-kratos/kratos/v2/log""github.com/go-kratos/kratos/v2/middleware/tracing""github.com/go-kratos/kratos/v2/transport/grpc""github.com/go-kratos/kratos/v2/transport/http""github.com/natefinch/lumberjack""go.uber.org/zap""go.uber.org/zap/zapcore"
)var sugarLogger *zap.SugaredLogger// go build -ldflags "-X main.Version=x.y.z"
var (// Name is the name of the compiled software.Name string// Version is the version of the compiled software.Version string// flagconf is the config flag.flagconf stringid, _ = os.Hostname()
)func init() {flag.StringVar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml")
}func newApp(logger log.Logger, hs *http.Server, gs *grpc.Server) *kratos.App {return kratos.New(kratos.ID(id),kratos.Name(Name),kratos.Version(Version),kratos.Metadata(map[string]string{}),kratos.Logger(logger),kratos.Server(hs,gs,),)
}func main() {encoder := zapcore.EncoderConfig{TimeKey: "t",LevelKey: "level",NameKey: "logger",CallerKey: "caller",MessageKey: "msg",StacktraceKey: "stack",EncodeTime: zapcore.ISO8601TimeEncoder,LineEnding: zapcore.DefaultLineEnding,EncodeLevel: zapcore.LowercaseLevelEncoder,EncodeDuration: zapcore.SecondsDurationEncoder,EncodeCaller: zapcore.FullCallerEncoder,}zlogger := zaplog.NewZapLogger(encoder,zap.NewAtomicLevelAt(zapcore.DebugLevel),zap.AddStacktrace(zap.NewAtomicLevelAt(zapcore.ErrorLevel)),zap.AddCaller(),zap.AddCallerSkip(2),zap.Development(),)zlog := log.NewHelper(zlogger)zlog.Infow("name", "kratos", "from", "opensource")//原有的输出到控制台上//logger := log.With(log.NewStdLogger(os.Stdout),//输出到日志中logger := log.With(zlogger,"ts", log.DefaultTimestamp,"caller", log.DefaultCaller,"service.id", id,"service.name", Name,"service.version", Version,"trace_id", tracing.TraceID(),"span_id", tracing.SpanID(),)c := config.New(config.WithSource(file.NewSource(flagconf),),)defer c.Close()//去掉初始化日志//InitLogger()//defer sugarLogger.Sync()//url := "www.baidu.com"///sugarLogger.Debugf("Trying to hit GET request for %s", url)if err := c.Load(); err != nil {panic(err)}var bc conf.Bootstrapif err := c.Scan(&bc); err != nil {panic(err)}app, cleanup, err := initApp(bc.Server, bc.Data, logger)if err != nil {panic(err)}defer cleanup()// start and wait for stop signalif err := app.Run(); err != nil {panic(err)}
}func InitLogger() {writeSyncer := getLogWriter()encoder := getEncoder()core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)logger := zap.New(core, zap.AddCaller())sugarLogger = logger.Sugar()
}func getEncoder() zapcore.Encoder {encoderConfig := zap.NewProductionEncoderConfig()encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoderencoderConfig.EncodeLevel = zapcore.CapitalLevelEncoderreturn zapcore.NewConsoleEncoder(encoderConfig)
}func getLogWriter() zapcore.WriteSyncer {dateTime := time.Now().Format("2006_01_02_15_04_05")lumberJackLogger := &lumberjack.Logger{Filename: "./log/" + dateTime + "test.log",MaxSize: 1, //默认1MBMaxBackups: 5,MaxAge: 30,Compress: false,}return zapcore.AddSync(lumberJackLogger)
}
在main函数中将元日志替换为zap日志
logger := log.With(zlogger,"ts", log.DefaultTimestamp,"caller", log.DefaultCaller,"service.id", id,"service.name", Name,"service.version", Version,"trace_id", tracing.TraceID(),"span_id", tracing.SpanID(),)
三.打印出来的日志