Golang 库: 为什么 Golang slog 库不支持 slog.Fatal API

原文链接: https://tangx.in/posts/2023/0...

使用 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"
  1. slog 默认日志级别info, 无法输出 DEBUG 日志。

  2. slog 默认不支持 Fatal API。

    • 换而言之, 无法使用 slog 终止进程了。

关闭 Fatal 这个我还能理解, 毕竟很多 初始化连接 需要关闭, 直接退出太不优雅了。

golang.org/x/exp/slog 中提到, OpenTelemetry 支持 TraceFatal, 但是 slog 并不支持, 但是可以通过对日志等级设置合适的值, OpenTelemetry 的日志等级也可以作为 slog 的日志等级

OpenTelemetry also has the names TRACE and FATAL, which slog does not. But those OpenTelemetry levels can still be represented as slog Levels by using the appropriate integers.

除此之外, 并没有其他关于 Fatal API 的讨论了。

我猜 Go 官网是希望我们, 在终止前做一些退出处理, 不要太过于暴力。

退出前释放资源

例如下面案例,

  1. 在程序中遇到了 panic
  2. recover 捕获后进行了资源释放操作,
  3. 最后在执行 退出
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 吗? 什么时候用?

前提条件, 根据 UNIX 约定,遇到错误的进程应尽早失败并返回非零退出代码。

  1. init() 函数中使用, 这时候 main() 还没调用。
  2. 明确知道错误发生原因, 并且无法挽回。 例如读取文件失败后, 没必要进行后续操作。
  3. 在不可逆的过程中发生错误。 例如 cp -f 复制文件且强制覆盖。 如果程序没有错误退出, 就是默认成功。
https://stackoverflow.com/a/3...

老麦
6 声望0 粉丝

一个运维