https://github.com/uber-go/zap
Zap是非常快的、结构化的,分日志级别的Go日志库。是现在的主流, 没有用反射
https://github.com/wangshibiaoFlytiger/apiproject/tree/master/log
1 安装
go get -u go.uber.org/zap
2 如何输出日志
package main
import "go.uber.org/zap"
func main() {
// 开发环境
logger1, _ := zap.NewDevelopment()
defer logger1.Sync()
logger1.Info("failed to fetch URL",
zap.String("url", "https://imooc.com"),
zap.Int("attempt", 3)) // 2021-11-16T10:58:24.906+0800 INFO zap_test/main.go:9 failed to fetch URL {"url": "https://imooc.com", "attempt": 3}
// 生产环境
logger2, _ := zap.NewProduction()
defer logger2.Sync()
// 普通logger2
logger2.Info("failed to fetch URL",
zap.String("url", "https://imooc.com"),
zap.Int("attempt", 3)) // {"level":"info","ts":1637031504.9066734,"caller":"zap_test/main.go:17","msg":"failed to fetch URL","url":"https://imooc.com","attempt":3}
// 使用语法糖
sugar := logger2.Sugar()
sugar.Infow("failed to fetch URL",
"url", "https://imooc.com",
"attempt", 3) // {"level":"info","ts":1637031504.9067116,"caller":"zap_test/main.go:23","msg":"failed to fetch URL","url":"https://imooc.com","attempt":3}
}
3 日志输出到文件
package main
import (
"go.uber.org/zap"
"time"
)
func NewLogger() (*zap.Logger, error) {
cfg := zap.NewProductionConfig()
cfg.OutputPaths = []string {
"./info.log",
}
return cfg.Build()
}
func main() {
logger, err := NewLogger()
if err != nil {
panic(err)
}
su := logger.Sugar()
defer su.Sync()
su.Info("failed to fetch URL",
"url", "https://immoc.com",
"attempt", 3,
"backoff", time.Second,
)
}
4 封装
package zlog
// 简单封装一下对 zap 日志库的使用
// 使用方式:
// zlog.Debug("hello", zap.String("name", "Kevin"), zap.Any("arbitraryObj", dummyObject))
// zlog.Info("hello", zap.String("name", "Kevin"), zap.Any("arbitraryObj", dummyObject))
// zlog.Warn("hello", zap.String("name", "Kevin"), zap.Any("arbitraryObj", dummyObject))
var logger *zap.Logger
func init() {
......
}
func getFileLogWriter() (writeSyncer zapcore.WriteSyncer) {
......
}
func Info(message string, fields ...zap.Field) {
callerFields := getCallerInfoForLog()
fields = append(fields, callerFields...)
logger.Info(message, fields...)
}
func Debug(message string, fields ...zap.Field) {
callerFields := getCallerInfoForLog()
fields = append(fields, callerFields...)
logger.Debug(message, fields...)
}
func Error(message string, fields ...zap.Field) {
callerFields := getCallerInfoForLog()
fields = append(fields, callerFields...)
logger.Error(message, fields...)
}
func Warn(message string, fields ...zap.Field) {
callerFields := getCallerInfoForLog()
fields = append(fields, callerFields...)
logger.Warn(message, fields...)
}
func getCallerInfoForLog() (callerFields []zap.Field) {
pc, file, line, ok := runtime.Caller(2) // 回溯两层,拿到写日志的调用方的函数信息
if !ok {
return
}
funcName := runtime.FuncForPC(pc).Name()
funcName = path.Base(funcName) //Base函数返回路径的最后一个元素,只保留函数名
callerFields = append(callerFields, zap.String("func", funcName), zap.String("file", file), zap.Int("line", line))
return
}