上一章节我们封装TO(测试对象),方便我们以后扩展其他被测的接口或协议。本章我们主要实现以下,我们的日志输出。在以前的章节中,我们都是使用go的fmt包进行日志输出(打印到控制台),在工作中我们都知道,我们的服务都是由日志文件,以及日志级别的。下面我们就实现以下,将指定的级别的日志,输出到日志文件中。
我们在项目中新建global目录并在global目录下新建log目录,结构如下:
kitchen-engine/global/log/logger.go
package log
import (
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
)
// 声明一个zap包的SugaredLogger指针
var Logger *zap.SugaredLogger
var Logger *zap.SugaredLogger
// 获取一个异步io.Write
func getWriteSyncer(path string, maxSize, maxBackups, maxAge int, compress bool) zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{}
// 日志文件的位置
if path == "" {
path = "./runner"
}
lumberJackLogger.Filename = path
// 在进行切割之前,日志文件的最大大小,MB
if maxSize != 0 {
lumberJackLogger.MaxSize = maxSize
}
// 保留旧文件的最大个数
if maxBackups != 0 {
lumberJackLogger.MaxBackups = maxBackups
}
// 旧文件保留的时间天数
if maxAge != 0 {
lumberJackLogger.MaxAge = maxAge
}
// 是否压缩/归档旧文件
if compress {
lumberJackLogger.Compress = true
}
return zapcore.AddSync(lumberJackLogger)
}
// InitLogger 初始化日志模块
func InitLogger() {
// 设置日志的基本格式,使用开发模式
encoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
// 大于等于warn的日志级别
errLogger := zap.LevelEnablerFunc(func(level zapcore.Level) bool {
return level >= zapcore.WarnLevel
})
// 小于等于warn的日志级别
infoLogger := zap.LevelEnablerFunc(func(level zapcore.Level) bool {
return level <= zapcore.WarnLevel
})
// 配置输出到控制台
consoleSyncer := zapcore.AddSync(os.Stdout)
// 详细日志输出到info日志文件
info := getWriteSyncer("./runner-go-info.log", 100, 5, 10, false)
// 错误日志输出到错误日志文件
errSync := getWriteSyncer("./runner-go-err.log", 100, 5, 10, false)
core := zapcore.NewTee(
zapcore.NewCore(encoder, info, infoLogger),
zapcore.NewCore(encoder, consoleSyncer, zap.DebugLevel),
zapcore.NewCore(encoder, errSync, errLogger))
Logger = zap.New(core, zap.AddCaller()).Sugar()
}
这样,我们就把日志的模块,配置完了。
我们可以使用单元测试,自测以下。在go中使用单元测试,我们直接新建一个
kitchen-engine/global/log/logger_test.go
package log
import (
"testing"
)
// 使用go单元测试,直接Test+方法名
func TestInitLogger(t *testing.T) {
// 初始化日志配置
InitLogger()
// 打印debug级别的日志
Logger.Debug("你好我好,大家好")
// 打印错误级别的日志
Logger.Error("错误哦错误")
}
然后,我们直接运行该方法即可,不用在main函数中去使用。这样,我们在控制台,可以看到如下日志:
=== RUN TestInitLogger
2023-06-15T14:05:49.896+0800 DEBUG log/logger_test.go:15 你好 我好,大家好
2023-06-15T14:05:49.910+0800 ERROR log/logger_test.go:16 错误 哦错误
--- PASS: TestInitLogger (0.02s)
PASS
Process finished with the exit code 0
同时在我们的log文件夹下,分别多了runner-go-info.log和runner-go-err.log
编辑
刚才我们使用单元测试对日志模块进行了自测,可以正常使用。
下面我们为了,更灵活的配置日志,我们采用配置文件的方式来进行配置。
在global目录下新建global/config/config.go
package config
import (
"flag"
"fmt"
)
import "github.com/spf13/viper"
var YC YamlConfig
type YamlConfig struct {
Log Log yaml:"log"
}
type Log struct {
Env string yaml:"env" // 环境
InfoLogPath string yaml:"info_log_path" // 详细日志的文件地址
ErrLogPath string yaml:"err_log_path" // 错误日志的文件地址
IsConsoleLog bool yaml:"is_console_log" // 是否将日志输出到控制台
}
// InitConfig 初始化YamlConfig结构体,将配置文件读取到内存中
func InitConfig() {
var file string
// go语言命令行工具
flag.StringVar(&file, "f", "../../open.yaml", "配置文件,默认为根目录下的open.yaml")
if !flag.Parsed() {
flag.Parse()
}
viper.SetConfigFile(file)
// 读取的配置文件为yaml文件类型
viper.SetConfigType("yaml")
if err := viper.ReadInConfig(); err != nil {
panic(fmt.Sprintf("读取配置文件: %s 失败!", file))
}
if err := viper.Unmarshal(&YC); err != nil {
panic(fmt.Sprintf("配置文件: %s, 匹配: %v类型失败!", file, YC))
}
fmt.Println(fmt.Sprintf("配置文件:%s初始化成功", file))
}
在项目的根目录,我们新建open.yaml(配置文件)。
log:
env: "test" # 环境
Info_log_path: "./runner-go-info.log" # 详细日志的文件地址
err_log_path: "./runner-go-err.log" # 错误日志的文件地址
is_console_log: true # 是否将日志输出到控制台
我们去main.go中对配置文件和日志配置,进行测试。
main.go
package main
import (
"kitchen-engine/global/config"
"kitchen-engine/global/log"
)
// 初始化函数,在main函数之前运行
func init() {
// 初始化配置信息
config.InitConfig()
// 初始化日志配置
log.InitLogger()
}
func main() {
log.Logger.Debug("yc: ", config.YC)
//// 一个类型中的字段,可以重置,也可以使用默认值,在go中,所有的类型的初始值,都是字段类型的0值,比如string的初始值是""空字符串,int类型的初始值是0等等
//httpClientSettings := model.HttpClientSettings{
// Name: "测试厨房",
// NoDefaultUserAgentHeader: true,
// MaxConnDuration: 1000,
// AdvancedOptions: model.AdvancedOptions{
// Tls: model.Tls{
// IsVerify: true,
// VerifyType: 1,
// },
// },
//}
//
//headers := []model.Header{
// model.Header{
// Field: "name",
// Value: "你好",
// },
//}
//
//httpRequest := model.HttpRequest{
// Url: "https://www.baidu.com",
// Method: "GET",
// HttpClientSettings: httpClientSettings,
// Headers: headers,
//}
//
//client.RequestHttp(httpRequest)
log.Logger.Info("欢迎使用zap日志")
}
这样,我们就可以修改我们的日志初始化的配置。
logger.go
// InitLogger 初始化日志模块
func InitLogger(yc config.YamlConfig) {
// 设置日志的基本格式,使用开发模式
encoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
// 大于等于warn的日志级别
errLogger := zap.LevelEnablerFunc(func(level zapcore.Level) bool {
return level >= zapcore.WarnLevel
})
// 小于等于warn的日志级别
infoLogger := zap.LevelEnablerFunc(func(level zapcore.Level) bool {
return level <= zapcore.WarnLevel
})
// 配置输出到控制台
consoleSyncer := zapcore.AddSync(os.Stdout)
// 详细日志输出到info日志文件
info := getWriteSyncer(yc.Log.InfoLogPath, 100, 5, 10, false)
// 错误日志输出到错误日志文件
errSync := getWriteSyncer(yc.Log.ErrLogPath, 100, 5, 10, false)
core := zapcore.NewTee(
zapcore.NewCore(encoder, info, infoLogger),
zapcore.NewCore(encoder, consoleSyncer, zap.DebugLevel),
zapcore.NewCore(encoder, errSync, errLogger))
Logger = zap.New(core, zap.AddCaller()).Sugar()
}
main.go
package main
import (
"kitchen-engine/global/config"
"kitchen-engine/global/log"
)
// 初始化函数,在main函数之前运行
func init() {
// 初始化配置信息
config.InitConfig()
// 初始化日志配置
log.InitLogger(config.YC)
}
今天的内容就到这里,其他配置项如果也想修改的,可以自行配置及变更。这样可以更方便、更灵活的使用。