1. 日志目录结果
└──logger
├── log
│ ├── test-2021-05-31T04-45-58.137.log
│ ├── test-2021-05-31T04-46-03.650.log
│ ├── test-2021-05-31T04-46-09.013.log
│ └── test.log
├── logger.go
└── logger_test.go
logger.go 文件
安装依赖
go get -u go.uber.org/zap
go get -u github.com/natefinch/lumberjack
package logger
// 安装以下依赖库
// go get -u go.uber.org/zap
// go get -u github.com/natefinch/lumberjack
import (
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
"path/filepath"
)
const DefaultLogPath = "/var/log/test" // 默认输出日志文件路径
type LogConfigs struct {
LogLevel string // 日志打印级别 debug info warning error
LogFormat string // 输出日志格式 logfmt, json
LogPath string // 输出日志文件路径
LogFileName string // 输出日志文件名称
LogFileMaxSize int // 【日志分割】单个日志文件最多存储量 单位(mb)
LogFileMaxBackups int // 【日志分割】日志备份文件最多数量
LogMaxAge int // 日志保留时间,单位: 天 (day)
LogCompress bool // 是否压缩日志
LogStdout bool // 是否输出到控制台
}
// InitLogger 初始化 log
func InitLogger(conf LogConfigs) error {
logLevel := map[string]zapcore.Level{
"debug": zapcore.DebugLevel,
"info": zapcore.InfoLevel,
"warn": zapcore.WarnLevel,
"error": zapcore.ErrorLevel,
}
writeSyncer, err := getLogWriter(conf) // 日志文件配置 文件位置和切割
if err != nil {
return err
}
encoder := getEncoder(conf) // 获取日志输出编码
level, ok := logLevel[conf.LogLevel] // 日志打印级别
if !ok {
level = logLevel["info"]
}
core := zapcore.NewCore(encoder, writeSyncer, level)
logger := zap.New(core, zap.AddCaller()) // zap.Addcaller() 输出日志打印文件和行数如: logger/logger_test.go:33
// 1. zap.ReplaceGlobals 函数将当前初始化的 logger 替换到全局的 logger,
// 2. 使用 logger 的时候 直接通过 zap.S().Debugf("xxx") or zap.L().Debug("xxx")
// 3. 使用 zap.S() 和 zap.L() 提供全局锁,保证一个全局的安全访问logger的方式
zap.ReplaceGlobals(logger)
//zap.L().Debug("")
//zap.S().Debugf("")
return nil
}
// getEncoder 编码器(如何写入日志)
func getEncoder(conf LogConfigs) zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder // log 时间格式 例如: 2021-09-11t20:05:54.852+0800
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // 输出level序列化为全大写字符串,如 INFO DEBUG ERROR
//encoderConfig.EncodeCaller = zapcore.FullCallerEncoder
//encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
if conf.LogFormat == "json" {
return zapcore.NewJSONEncoder(encoderConfig) // 以json格式写入
}
return zapcore.NewConsoleEncoder(encoderConfig) // 以logfmt格式写入
}
// getLogWriter 获取日志输出方式 日志文件 控制台
func getLogWriter(conf LogConfigs) (zapcore.WriteSyncer, error) {
// 判断日志路径是否存在,如果不存在就创建
if exist := IsExist(conf.LogPath); !exist {
if conf.LogPath == "" {
conf.LogPath = DefaultLogPath
}
if err := os.MkdirAll(conf.LogPath, os.ModePerm); err != nil {
conf.LogPath = DefaultLogPath
if err := os.MkdirAll(conf.LogPath, os.ModePerm); err != nil {
return nil, err
}
}
}
// 日志文件 与 日志切割 配置
lumberJackLogger := &lumberjack.Logger{
Filename: filepath.Join(conf.LogPath, conf.LogFileName), // 日志文件路径
MaxSize: conf.LogFileMaxSize, // 单个日志文件最大多少 mb
MaxBackups: conf.LogFileMaxBackups, // 日志备份数量
MaxAge: conf.LogMaxAge, // 日志最长保留时间
Compress: conf.LogCompress, // 是否压缩日志
}
if conf.LogStdout {
// 日志同时输出到控制台和日志文件中
return zapcore.NewMultiWriteSyncer(zapcore.AddSync(lumberJackLogger), zapcore.AddSync(os.Stdout)), nil
} else {
// 日志只输出到日志文件
return zapcore.AddSync(lumberJackLogger), nil
}
}
// IsExist 判断文件或者目录是否存在
func IsExist(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}
3. logger_test.go 文件
package logger
import (
"errors"
"go.uber.org/zap"
"testing"
"time"
)
func TestInitLogger(t *testing.T) {
// 1. 配置log参数
conf := LogConfigs{
LogLevel: "debug", // 输出日志级别 "debug" "info" "warn" "error"
LogFormat: "logfmt", // 输出日志格式 logfmt, json
LogPath: "./log", // 输出日志文件位置
LogFileName: "test.log", // 输出日志文件名称
LogFileMaxSize: 1, // 输出单个日志文件大小,单位MB
LogFileMaxBackups: 10, // 输出最大日志备份个数
LogMaxAge: 1000, // 日志保留时间,单位: 天 (day)
LogCompress: false, // 是否压缩日志
LogStdout: true, // 是否输出到控制台
}
// 2. 初始化log
if err := InitLogger(conf); err != nil {
t.Fatal(err)
}
// 3. 调用 Logger 打印日志测试
zap.S().Infof("测试 Infof 用法:%s", "111") // logger Infof 用法
zap.S().Debugf("测试 Debugf 用法:%s", "111") // logger Debugf 用法
go func() {
for i := 0; i < 100000; i++ {
zap.S().Infof("(1)协程内部调用测试 Infof 用法:%s", "111")
time.Sleep(time.Millisecond)
}
}()
zap.S().Errorf("测试 Errorf 用法:%s", "111") // logger Errorf 用法
zap.S().Warnf("测试 Warnf 用法:%s", "111") // logger Warnf 用法
zap.S().Infof("测试 Infof 用法:%s, %d, %v, %f", "111", 1111, errors.New("collector returned no data"), 3333.33)
// logger With 用法
logger := zap.S().With("collector", "cpu", "name", "主机")
logger.Infof("测试 (With + Infof) 用法:%s", "测试")
zap.S().Errorf("测试 Errorf 用法:%s", "111")
go func() {
for i := 0; i < 100000; i++ {
zap.S().Infof("(2)协程内部调用测试 Infof 用法:%s", "111")
time.Sleep(time.Millisecond)
}
}()
time.Sleep(time.Minute)
}
4. 输出日志文件 test.log
{"level":"INFO","ts":"2021-03-12T16:43:49.023+0800","caller":"logger/logger_test.go:28","msg":"测试 Infof 用法:111"}
{"level":"ERROR","ts":"2021-03-12T16:43:49.023+0800","caller":"logger/logger_test.go:30","msg":"测试 Errorf 用法:111"}
{"level":"WARN","ts":"2021-03-12T16:43:49.023+0800","caller":"logger/logger_test.go:31","msg":"测试 Warnf 用法:111"}
{"level":"INFO","ts":"2021-03-12T16:43:49.024+0800","caller":"logger/logger_test.go:32","msg":"测试 Infof 用法:111, 1111, collector returned no data, 3333.330000"}
{"level":"INFO","ts":"2021-03-12T16:43:49.024+0800","caller":"logger/logger_test.go:35","msg":"测试 (With + Infof) 用法:测试","collector":"cpu","name":"主机"}
2021-03-12T16:51:39.740+0800 INFO logger/logger_test.go:28 测试 Infof 用法:111
2021-03-12T16:51:39.741+0800 ERROR logger/logger_test.go:30 测试 Errorf 用法:111
2021-03-12T16:51:39.741+0800 WARN logger/logger_test.go:31 测试 Warnf 用法:111
2021-03-12T16:51:39.741+0800 INFO logger/logger_test.go:32 测试 Infof 用法:111, 1111, collector returned no data, 3333.330000
2022-03-12T16:51:39.741+0800 INFO logger/logger_test.go:35 测试 (With + Infof) 用法:测试 {"collector": "cpu", "name": "主机"}
|
请发表评论