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 排版

相关推荐
沈韶珺1 小时前
Visual Basic语言的云计算
开发语言·后端·golang
沈韶珺1 小时前
Perl语言的函数实现
开发语言·后端·golang
美味小鱼2 小时前
Rust 所有权特性详解
开发语言·后端·rust
我的K84092 小时前
Spring Boot基本项目结构
java·spring boot·后端
慕璃嫣3 小时前
Haskell语言的多线程编程
开发语言·后端·golang
晴空๓3 小时前
Spring Boot项目如何使用MyBatis实现分页查询
spring boot·后端·mybatis
Hello.Reader7 小时前
深入浅出 Rust 的强大 match 表达式
开发语言·后端·rust
customer0810 小时前
【开源免费】基于SpringBoot+Vue.JS体育馆管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
计算机-秋大田13 小时前
基于微信小程序的电子竞技信息交流平台设计与实现(LW+源码+讲解)
spring boot·后端·微信小程序·小程序·课程设计