在软件开发过程中,需要进行关键日志记录,便于后期的审计和排错。
一个好的日志记录器应该具备以下功能:
配置日志输出文件
func SetupLogger() {
logFileLocation, _ := os.OpenFile("./test.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0744)
log.SetOutput(logFileLocation)
}
编写示例,建立一个到 URL 的 HTTP 连接,记录状态码/错误记录到日志文件
func simpleHttpGet(url string) {
resp, err := http.Get(url)
if err != nil {
log.Printf("Error fetching url %s : %s", url, err.Error())
} else {
log.Printf("Status Code for %s : %s", url, resp.Status)
resp.Body.Close()
}
}
main 函数,执行示例
func main() {
SetupLogger()
simpleHttpGet("www.google.com")
simpleHttpGet("http://www.google.com")
}
看到 test.log
文件被创建,并且记录了下面的内容
2022/04/22 11:33:52 Error fetching url www.google.com : Get "www.google.com": unsupported protocol scheme ""
2022/04/22 11:33:53 Status Code for http://www.google.com : 200 OK
go get -u go.uber.org/zap
Zap 提供两种类型的日志记录器- Sugared Logger
和 Logger
在性能很好但不是很关键的上下文中,使用 SugaredLogger
。它比其他结构化日志记录包快 4-10 倍,并且支持结构化和 printf 风格的日志记录
在每一微秒和每一次内存分配都很重要的上下文中,使用 Logger
。甚至比 SugaredLogger
更快,内存分配次数也更少,但它只支持强类型的结构化日志记录
zap.NewProduction()/zap.NewDevelopment()
或者 zap.Example()
创建一个 Logger
logger
。唯一的区别在于它将记录的信息不同。例如 production logger
默认记录调用函数信息、日期和时间等Logger
调用 Info/Error
等console
界面var logger *zap.Logger
func main() {
InitLogger()
defer logger.Sync()
simpleHttpGet("www.google.com")
simpleHttpGet("http://www.google.com")
}
func InitLogger() {
logger, _ = zap.NewProduction()
}
func simpleHttpGet(url string) {
resp, err := http.Get(url)
if err != nil {
logger.Error(
"Error fetching url..",
zap.String("url", url),
zap.Error(err))
} else {
logger.Info("Success..",
zap.String("statusCode", resp.Status),
zap.String("url", url))
resp.Body.Close()
}
}
logger
的. Sugar()
方法来获取一个 SugaredLogger
SugaredLogger
以 printf
格式记录语句var sugarLogger *zap.SugaredLogger
func main() {
InitLogger()
defer sugarLogger.Sync()
simpleHttpGet("www.google.com")
simpleHttpGet("http://www.google.com")
}
func InitLogger() {
logger, _ := zap.NewProduction()
sugarLogger = logger.Sugar()
}
func simpleHttpGet(url string) {
sugarLogger.Debugf("Trying to hit GET request for %s", url)
resp, err := http.Get(url)
if err != nil {
sugarLogger.Errorf("Error fetching URL %s : Error = %s", url, err)
} else {
sugarLogger.Infof("Success! statusCode = %s for URL %s", resp.Status, url)
resp.Body.Close()
}
}
NewJSONEncoder()
,并使用预先设置的zapcore.AddSync()
函数并且将打开的文件句柄传进去var logger *zap.Logger
func main() {
InitLogger()
defer logger.Sync()
simpleHttpGet("www.google.com")
simpleHttpGet("http://www.google.com")
}
func InitLogger() {
writeSyncer := getLogWriter()
encoder := getEncoder()
core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
logger := zap.New(core)
// sugarLogger = logger.Sugar()
}
func getEncoder() zapcore.Encoder {
return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
}
func getLogWriter() zapcore.WriteSyncer {
file, _ := os.Create("./test.log")
return zapcore.AddSync(file)
}
func simpleHttpGet(url string) {
resp, err := http.Get(url)
if err != nil {
logger.Error(
"Error fetching url..",
zap.String("url", url),
zap.Error(err))
} else {
logger.Info("Success..",
zap.String("statusCode", resp.Status),
zap.String("url", url))
resp.Body.Close()
}
}
将 JSON Encoder 更改为普通的 Log Encoder,只需要将 NewJSONEncoder()
更改为NewConsoleEncoder()
Lumberjack
是一个 Go 包,用于日志切割归档功能
zap 不支持日志切割归档,lumberjack 也是 zap 官方推荐的
通过 zapcore.AddSync
加入 lumberjack
功能
// lumberjack.Logger is already safe for concurrent use, so we don't need to
// lock it.
w := zapcore.AddSync(&lumberjack.Logger{
Filename: "/var/log/myapp/foo.log",
MaxSize: 500, // megabytes
MaxBackups: 3,
MaxAge: 28, // days
})
core := zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
w,
zap.InfoLevel,
)
logger := zap.New(core)
Lumberjack Logger采用以下属性作为输入:
完整代码:https://gitee.com/MoGD/go-study/blob/main/go-zap/sugaredLogger/main.go
[1] 在Go语言项目中使用Zap日志库(李文周)
[2] Go Logger
[3] Go zap