官方文档
https://go-kratos.dev/zh-cn/docs/component/log/
主要是看文档为主
写文件
// 输出到 ./server.log 文件 f, err := os.OpenFile("server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { return }
logger和helper
通过阅读kratos脚手架生成的代码发现,logger是在main函数当中注入进去的,biz和data在构造函数时Helper类型
main统一了日志的接入方式biz和data增强日志的使用
Helper更加全面,有数据脱敏,字段级别过滤,语法糖等功能
一般在biz或者data的构造函数添加字段的过滤
配合zap使用
github参考代码
https://github.com/go-kratos/kratos/blob/main/contrib/log/zap/zap.go
定义配置
log:
format: "text" # 日志格式,text, json
log_file: "logs/server.log" # 日志文件
max_size: 100 # 单个文件最大 10MB
max_backups: 10 # 保留 10 个旧文件
max_age: 30 # 保留 30 天
compress: true # 启用压缩
封装logger
internal/pkg/logger/zap.go
实现Log方法即可
package logger
import (
"fmt"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/go-kratos/kratos/v2/log"
)
var _ log.Logger = (*Logger)(nil)
type Logger struct {
log *zap.Logger
msgKey string
}
type Option struct {
Format string
Level string
LogFile string
MaxSize int32
MaxBackups int32
MaxAge int32
Compress bool
}
func NewOption(format string, level string, logFile string, maxSize int32, maxBackups int32, maxAge int32, compress bool) *Option {
return &Option{
Format: format,
Level: level,
LogFile: logFile,
MaxSize: maxSize,
MaxBackups: maxBackups,
MaxAge: maxAge,
Compress: compress,
}
}
func NewZapLogger(opts *Option) *Logger {
var encoder zapcore.Encoder
if opts.Format == "text" {
encoder = zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
} else {
encoder = zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
}
core := zapcore.NewCore(encoder, getLogWriter(opts), parseLogLevel(opts.Level))
return &Logger{log: zap.New(core), msgKey: log.DefaultMessageKey}
}
func (l *Logger) Log(level log.Level, keyvals ...any) error {
// If logging at this level is completely disabled, skip the overhead of
// string formatting.
if zapcore.Level(level) < zapcore.DPanicLevel && !l.log.Core().Enabled(zapcore.Level(level)) {
return nil
}
var (
msg = ""
keylen = len(keyvals)
)
if keylen == 0 || keylen%2 != 0 {
l.log.Warn(fmt.Sprint("Keyvalues must appear in pairs: ", keyvals))
return nil
}
data := make([]zap.Field, 0, (keylen/2)+1)
for i := 0; i < keylen; i += 2 {
if keyvals[i].(string) == l.msgKey {
msg, _ = keyvals[i+1].(string)
continue
}
data = append(data, zap.Any(fmt.Sprint(keyvals[i]), keyvals[i+1]))
}
switch level {
case log.LevelDebug:
l.log.Debug(msg, data...)
case log.LevelInfo:
l.log.Info(msg, data...)
case log.LevelWarn:
l.log.Warn(msg, data...)
case log.LevelError:
l.log.Error(msg, data...)
case log.LevelFatal:
l.log.Fatal(msg, data...)
}
return nil
}
func (l *Logger) Sync() error {
return l.log.Sync()
}
func (l *Logger) Close() error {
return l.Sync()
}
internal/pkg/logger/log.go
package logger
import (
"io"
"os"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
func parseLogLevel(level string) zapcore.Level {
switch level {
case "debug":
return zapcore.DebugLevel
case "info":
return zapcore.InfoLevel
case "warn":
return zapcore.WarnLevel
case "error":
return zapcore.ErrorLevel
}
return zapcore.InfoLevel
}
// 全量日志
func getLogWriter(opt *Option) zapcore.WriteSyncer {
logger := &lumberjack.Logger{
Filename: opt.LogFile,
MaxSize: int(opt.MaxSize),
MaxBackups: int(opt.MaxBackups),
MaxAge: int(opt.MaxAge),
Compress: opt.Compress,
}
ws := io.MultiWriter(logger, os.Stdout)
return zapcore.AddSync(ws)
}
在main.go引入
// zap 封装的日志 logger := log.With(logger.NewZapLogger(logger.NewOption(bc.Log)), "caller", log.DefaultCaller, "service.id", id, "service.name", Name, "service.version", Version, "trace.id", tracing.TraceID(), "span.id", tracing.SpanID(), )