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

相关推荐
码蜂窝编程官方5 分钟前
【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的虎鲸旅游攻略网的设计与实现
java·vue.js·spring boot·后端·spring·旅游
hummhumm24 分钟前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
J老熊34 分钟前
JavaFX:简介、使用场景、常见问题及对比其他框架分析
java·开发语言·后端·面试·系统架构·软件工程
AuroraI'ncoding40 分钟前
时间请求参数、响应
java·后端·spring
好奇的菜鸟1 小时前
Go语言中的引用类型:指针与传递机制
开发语言·后端·golang
Alive~o.01 小时前
Go语言进阶&依赖管理
开发语言·后端·golang
许苑向上1 小时前
Dubbo集成SpringBoot实现远程服务调用
spring boot·后端·dubbo
郑祎亦2 小时前
Spring Boot 项目 myblog 整理
spring boot·后端·java-ee·maven·mybatis
本当迷ya2 小时前
💖2025年不会Stream流被同事排挤了┭┮﹏┭┮(强烈建议实操)
后端·程序员
计算机毕设指导63 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea