一.如何在kratos框架中使用
参考官方文档中描述,为了方便业务自适配不同的 log 接入使用,Logger 只包含了最简单的 Log 接口。当业务需要在 Kratos 框架内部使用自定义的 log的时候,只需要简单实现方法即可。日志库较为公用建议放在kit基础库中方便其他微服务引用。在kratos日志中,很多时候是输出到控制台的,但是实践中更多的是为了打印到文本中。
1.实现log接口并配置zap日志库编码
package log
import (
"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.Logger
Sync 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 MB
MaxBackups: 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 appear
var data []zap.Field
for 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 main
import (
"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 string
id, _ = 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.Bootstrap
if 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 signal
if 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.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
return 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, //默认1MB
MaxBackups: 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(),
)
三.打印出来的日志