写在文章开头
即使系统没有任何表现,程序也可能会有一些潜藏的隐患,所以通过日志来监控程序的运行就显得尤为重要,对此笔者便基于此文来聊聊go语言中的日志的配置和使用。
Hi,我是 sharkChili ,是个不断在硬核技术上作死的 java coder ,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili 。
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 "加群" 即可和笔者和笔者的朋友们进行深入交流。
go语言日志配置和使用详解
基本配置
和使用Java
配置log4j
一样,go语言同样是需要对日志进行配置,在main函数执行前,go语言会通过init完成一些初始化工作,所以我们就可以在此函数进行日志配置工作。 如下所示,我们通过SetPrefix
配置了日志的基本前缀为TRACE:
,并结合SetFlags
设定了日志的基本格式。
c
import "log"
// init 在main前执行
func init() {
//设置日志前缀
log.SetPrefix("TRACE:")
//设置日志格式,通过异或运算拼接
log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
}
然后我们就可以用这种格式输出一段日志:
c
func main() {
log.Println("hello go")
}
可以看到日志的输出结果,严格按照SetPrefix
和SetFlags
设置格式标准输出了我们的日志信息:
go
TRACE:2024/04/09 23:25:04.560405 main.go:14: hello go
go语言日志配置参数
我们对SetFlags
的入参展开说明,它是go语言的内置常量,以笔者的配置为例,笔者打印的要求格式是:
Ldate
:2009/01/23作为年月日的打印格式Lmicroseconds
:01:23:23.123123作为时分秒的打印格式Lshortfile
:打印日志时,输出简要的代码文件和行数,最后输出打印信息。
最后通过异或运算符将这三个参数拼接起来:
c
log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
这里也补充一下为什么可以用异或运算符拼接配置的原因,因为这些日志参数的常量都会对应一个不同的二进制数,通过不同的二进制数对应到不同的配置项从而生成日志配置。
这里关于每个配置的具体含义在go语言
的log.go
中有了详细的说明,笔者这里就不多赘述了:
打印不同级别的日志
当我们希望打印一行语句并进行换行,就可以使用日志的Println
:
c
log.Println("打印普通日志消息")
而Fatalln
打印完成之后会调用os.Exit(1)
退出,不再执行后续的语句,这也就是为什么对于异常我们可以使用Fatalln进行打印:
c
log.Fatalln("报异常了")
log.Println("打印普通日志消息")
输出结果如下所示,可以看到因为Fatalln
日志会调用os.Exit(1)
,使得后续的语句不再执行:
yaml
2024/04/09 23:33:07 报异常了
如果我们希望打印的错误显示异常的堆栈信息,我们可以通过Panicln
进行打印,该方法会在打印堆栈信息后,除非程序执行recover,否则就会调用panic(s)将调用堆栈终止:
c
log.Panicln("抛异常了")
对应输出结果如下:
javascript
2024/04/09 23:36:18 报异常了
panic: 报异常了
goroutine 1 [running]:
log.Panicln({0xc00011df60?, 0x0?, 0x0?})
D:/myinstall/Go/src/log/log.go:398 +0x65
main.main()
F:/github/test/main.go:6 +0x45
企业级日志配置
上述的日志只能标准输出的终端上,如果我们希望打印到日志里便于后续排查就需要定制日志记录器,对此笔者定义了4种日志的配置范例。 我们希望将错误的日志输出到文件上,我们首先在全局声明一个错误的日志变量的指针:
javascript
var (
//......其他级别的日志
Error *log.Logger
)
所以笔者通过OpenFile
配置了一个可以创建(os.O_CREATE)
、写(os.O_WRONLY)
、追加(os.O_APPEND
权限的文件error.txt
,注意如果创建失败则将错误输出:
lua
//创建一个有读写的错误日志文件
file, err := os.OpenFile("error.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalln("文件创建失败")
}
我们再来看看另一种日志的配置,通过log.New
的三个配置决定日志的输出目的地,前缀、格式,如下所示,对应的日志就是不输出,且前缀为Trance,格式为2009/01/23 01:23:23.123123 d.go:23
格式的日志:
c
Trance *log.Logger //记录所有日志
//不输出
Trance = log.New(io.Discard, "Trance:", log.Ldate|log.Lmicroseconds|log.Lshortfile)
同理基于这种配置方式我们给出完整的企业级日志配置,读者可以结合注释参考:
c
import (
"io"
"log"
"os"
)
var (
Trance *log.Logger //记录所有日志
Info *log.Logger //重要的信息
Warning *log.Logger //需要注意的信息
Error *log.Logger //非常严重的信息
)
// init 在main前执行
func init() {
//创建一个有读写的错误日志文件
file, err := os.OpenFile("error.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalln("文件创建失败")
}
//不输出
Trance = log.New(io.Discard, "Trance:", log.Ldate|log.Lmicroseconds|log.Lshortfile)
//仅仅标准输出打印info和告警信息
Info = log.New(os.Stdout, "Info:", log.Ldate|log.Lmicroseconds|log.Lshortfile)
Warning = log.New(os.Stdout, "Warn:", log.Ldate|log.Lmicroseconds|log.Lshortfile)
//输出到文件和标准错误输出的日志记录其配置
Error = log.New(io.MultiWriter(file, os.Stderr), "Fatal:", log.Ldate|log.Lmicroseconds|log.Lshortfile)
}
对应使用实例和输出结果如下:
javascript
func main() {
Trance.Println("这段不会打印")
Info.Println("仅在标准输出打印")
Warning.Println("告警信息")
Error.Println("报错信息")
}
输出结果:
go
Info:2024/04/09 23:50:38.110848 main.go:34: 仅在标准输出打印
Warn:2024/04/09 23:50:38.117391 main.go:35: 告警信息
Fatal:2024/04/09 23:50:38.118023 main.go:36: 报错信息
小结
以上便是go语言
企业级日志配置的基本实践,笔者通过不同的参数和api展示的日志配置时基本的技巧和场景,希望对你有帮助。
我是 sharkchili ,CSDN Java 领域博客专家 ,开源项目---JavaGuide contributor ,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。 因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 "加群" 即可和笔者和笔者的朋友们进行深入交流。
参考
《go in action》
本文使用 markdown.com.cn 排版