Golang 库: 为什么 Golang slog 库不支持 Fatal
原文链接: https://tangx.in/posts/2023/01/06/why-dont-golang-slog-support-fatal-api/
使用 slog
默认不支持 Fatal
如果直接把 slog
当成 log
使用, 会有一点点头疼
func main() {
slog.Debug("debug")
slog.Info("info")
slog.Warn("warn")
slog.Error("err", fmt.Errorf("game over"))
// slog.Fatal("don't support")
}
// 2023/01/06 07:41:50 INFO info
// 2023/01/06 07:41:50 WARN warn
// 2023/01/06 07:41:50 ERROR err err="game over"
slog
默认日志级别 是info
, 无法输出DEBUG
日志。- 需要自定义
handler
实现日志级别判断。参考 Golang 库: 怎么使用 golang slog 设置日志 Debug 等级[1]
- 需要自定义
slog
默认不支持Fatal
API。- 换而言之, 无法使用
slog
终止进程了。
- 换而言之, 无法使用
关闭 Fatal
这个我还能理解, 毕竟很多 初始化连接 需要关闭, 直接退出太不优雅了。
在 golang.org/x/exp/slog
中提到, OpenTelemetry 支持 Trace
和 Fatal,
但是 slog
并不支持, 但是可以通过对日志等级设置合适的值, OpenTelemetry 的日志等级也可以作为 slog 的日志等级。
OpenTelemetry
also has the namesTRACE
andFATAL
, which slog does not. But those OpenTelemetry levels can still be represented as slog Levels by using the appropriate integers.
除此之外, 并没有其他关于 Fatal API
的讨论了。
我猜 Go 官网是希望我们, 在终止前做一些退出处理, 不要太过于暴力。
退出前释放资源
例如下面案例,
- 在程序中遇到了
panic
, - 被
recover
捕获后进行了资源释放操作, - 最后在执行 退出
func main() {
initConn()
defer func() {
releaseConn()
if err := recover(); err != nil {
slog.Warn("Fatal", "panic", err)
os.Exit(1)
}
}()
if err := do(); err != nil {
panic(err)
}
}
func do() error {
slog.Info("do logic statement")
return fmt.Errorf("game over")
}
// 初始化连接
func initConn() {
slog.Info("connect to redis")
}
// 释放连接
func releaseConn() {
slog.Warn("disconnect from redis")
}
// 2023/01/06 08:07:01 INFO connect to redis
// 2023/01/06 08:07:01 INFO do logic statement
// 2023/01/06 08:07:01 WARN disconnect from redis
// 2023/01/06 08:07:01 WARN Fatal panic="game over"
// exit status 1
加入一定要强制退出怎么办?
那如果一定要退出怎么办了?可能就只有自己调 os.Exit(n)
了
func main() {
slog.Error("err", fmt.Errorf("game over"))
os.Exit(1)
// skip
slog.Debug("debug")
slog.Info("info")
slog.Warn("warn")
}
// 2023/01/06 07:53:16 ERROR err err="game over"
// exit status 1
什么时候应该是用 Fatal
在找资料的时候, 在 StackOverflow 上找到一个问题 应该使用 log.Fatal 吗?什么时候用?[2]
前提条件, 根据 UNIX
约定,遇到错误的进程应尽早失败并返回非零退出代码。
- 在
init()
函数中使用, 这时候main()
还没调用。 - 明确知道错误发生原因, 并且无法挽回。例如读取文件失败后, 没必要进行后续操作。
- 在不可逆的过程中发生错误。例如
cp -f
复制文件且强制覆盖。如果程序没有错误退出, 就是默认成功。
https://stackoverflow.com/a/33890104
参考资料
[1]
Golang 库: 怎么使用 golang slog 设置日志 Debug 等级: https://tangx.in/posts/2023/01/06/how-to-set-debug-level-in-golang-slog/
[2]
应该使用 log.Fatal 吗?什么时候用?: https://stackoverflow.com/questions/33885235/should-a-go-package-ever-use-log-fatal-and-when