Go语言企业级日志管理

写在文章开头

即使系统没有任何表现,程序也可能会有一些潜藏的隐患,所以通过日志来监控程序的运行就显得尤为重要,对此笔者便基于此文来聊聊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")
}

可以看到日志的输出结果,严格按照SetPrefixSetFlags设置格式标准输出了我们的日志信息:

go 复制代码
TRACE:2024/04/09 23:25:04.560405 main.go:14: hello go

go语言日志配置参数

我们对SetFlags的入参展开说明,它是go语言的内置常量,以笔者的配置为例,笔者打印的要求格式是:

  1. Ldate:2009/01/23作为年月日的打印格式
  2. Lmicroseconds :01:23:23.123123作为时分秒的打印格式
  3. 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展示的日志配置时基本的技巧和场景,希望对你有帮助。

我是 sharkchiliCSDN Java 领域博客专家开源项目---JavaGuide contributor ,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。 因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 "加群" 即可和笔者和笔者的朋友们进行深入交流。

参考

《go in action》

本文使用 markdown.com.cn 排版

相关推荐
KYGALYX19 分钟前
服务异步通信
开发语言·后端·微服务·ruby
掘了24 分钟前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法1 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
Moment1 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
Cobyte2 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc
程序员侠客行3 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
Honmaple3 小时前
QMD (Quarto Markdown) 搭建与使用指南
后端
PP东3 小时前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
invicinble4 小时前
springboot的核心实现机制原理
java·spring boot·后端
全栈老石4 小时前
Python 异步生存手册:给被 JS async/await 宠坏的全栈工程师
后端·python