Using Go slog logging package ("log/slog"), I am looking for a way to change the log level of a logger during runtime?
Is it possible? I spent few hours playing with it but found no way to do that.

更新1-使用3个记录器运行应用程序并使用HTTP更改级别

下面是我根据Peter的答案编写的代码. 我做HTTP呼叫,就像 http://localhost:8080/changeLogLevel?logger=TCP&level=ERROR.

package main

import (
    "log"
    "log/slog"
    "net/http"
    "os"
    "strings"
    "time"
)

func main() {
    // Create a LevelVar variable and initialize it to DEBUG.

    // Create the template logger with info
    tcpLvl := new(slog.LevelVar)
    tcpLvl.Set(slog.LevelDebug)

    dbLvl := new(slog.LevelVar)
    dbLvl.Set(slog.LevelDebug)

    mqLvl := new(slog.LevelVar)
    mqLvl.Set(slog.LevelDebug)

    tcpLogger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
        Level: tcpLvl,
    }))

    mqLogger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
        Level: mqLvl,
    }))


    // Create the MQLogger.
    dbLogger :=  slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
        Level: dbLvl,
    }))

    // Create a goroutine that prints debug messages to the 3 loggers.
    go func() {
        levels := map[string]slog.Level{
            "DEBUG":  slog.LevelDebug,
            "WARN": slog.LevelWarn,
            "INFO": slog.LevelInfo,
            "ERROR": slog.LevelError,
        }
        for {
            for levelStr, numericLevel := range levels {
                log.Printf("Is: %s enabled for tcpLogger? %v \n", levelStr, tcpLogger.Enabled(nil, numericLevel))
            }
            dbLogger.Debug("This is a debug message from the DBLogger.")
            tcpLogger.Debug("This is a debug message from the TCPLogger.")
            mqLogger.Debug("This is a debug message from the MQLogger.")
            log.Println("----------------------------------------------------")
            time.Sleep(10 * time.Second)
        }
    }()
    // Create an HTTP server.
    http.HandleFunc("/changeLogLevel", func(w http.ResponseWriter, r *http.Request) {
        // Get the logger name from the request.
        log.Println("----- Got HTTP call -------")
        loggerName := r.URL.Query().Get("logger")

        // Get the new log level from the request.
        newLogLevelStr := r.URL.Query().Get("level")
        var level slog.Level
        log.Printf("Incoming log level  is %v\n", newLogLevelStr)
        switch strings.ToUpper(newLogLevelStr) {
        case "DEBUG":
            level = slog.LevelDebug
        case "WARNING":
            level = slog.LevelWarn
        case "ERROR":
            level = slog.LevelError
        case "INFO":
            level = slog.LevelInfo
        default:
            {
                w.WriteHeader(http.StatusBadRequest)
                w.Write([]byte("Invalid level name"))
                return
            }

        }

        log.Printf("Incoming logger name is %v\n", loggerName)
        switch strings.ToUpper(loggerName) {
        case "DB":
            dbLvl.Set(level)
        case "TCP":
            log.Printf("Going to set the TCP logger level to %v\n", level)
            tcpLvl.Set(level)
        case "MQ":
            mqLvl.Set(level)
        default:
            w.WriteHeader(http.StatusBadRequest)
            w.Write([]byte("Invalid logger name"))
            return
        }

        w.WriteHeader(http.StatusOK)
    })

    // Start the HTTP server.
    http.ListenAndServe(":8080", nil)
}

更新2-基本示例

下面的代码按预期工作.

package main

import (
    "log"
    "log/slog"
    "os"
)

func main() {
    log.Println("slog chaqnge level demo")
    lvl := new(slog.LevelVar)
    lvl.Set(slog.LevelInfo)

    logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
        Level: lvl,
    }))
    logger.Info("Info msg")
    logger.Debug("Debug msg - you will NOT see me")
    lvl.Set(slog.LevelDebug)
    logger.Debug("Debug msg - you will see me")

}

输出

2009/11/10 23:00:00 slog chaqnge level demo
time=2009-11-10T23:00:00.000Z level=INFO msg="Info msg"
time=2009-11-10T23:00:00.000Z level=DEBUG msg="Debug msg - you will see me"

推荐答案

内置处理程序的构造函数都带有HandlerOptions参数.HandlerOptions有一个级别字段,您可以使用它来动态更改级别.

type HandlerOptions struct {
    // Level reports the minimum record level that will be logged.
    // The handler discards records with lower levels.
    // If Level is nil, the handler assumes LevelInfo.
    // The handler calls Level.Level for each record processed;
    // to adjust the minimum level dynamically, use a LevelVar.
    Level Leveler

    // ...
}

因此,只需在创建记录器时设置一个LevelVar:

lvl := new(slog.LevelVar)
lvl.Set(slog.LevelInfo)

logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
    Level: lvl,
}))

// later ...

lvl.Set(slog.LevelDebug)

如果您正在实现您自己的处理程序,Enable方法将确定日志(log)级别,并且您也可以在那里轻松地使用LevelVar:

type MyHandler struct {
    level slog.Leveler
}

func (h *MyHandler) Enabled(_ context.Context, level slog.Level) bool {
    return level >= h.level.Level()
}

Go相关问答推荐

Golang regexpp:获取带有右括号的单词

如何使用Docker Compose配置Go,使main. go文件位于/CMD文件夹中

我不能让GIO画一个按钮

如何使用Promela建模语言对Golang RWLock进行建模

无法使用Segentio;S Kafka-Go连接到融合的Kafka

如何修复proxyconnect tcp:tls:第一条记录看起来不像tls握手

是否可以使用标准库构建 Go 二进制文件?

如何解决构建Docker Compose时的权限被拒绝问题

如何为ANTLR4目标Go调试监听器

golang / urfave.cli:无法手动设置标志

有没有办法在 Golang 中使用带有 go-simple-mail lib 的代理?

Go 中的 Azure JWT 验证不起作用

如何从 Go 中的 `HijackedResponse` 中删除 Cursor Position ANSI 转义码?

在 Go 中公开公共 JWK

转换朴素递归硬币问题时的记忆错误

如何 Select 前 N 个元素 Gin-Gorm

Golang 使用 docker 将敏感数据作为参数传递

测试包外文件时的 Golang 测试覆盖率

我应该明确地创建一个与Belongs To或Has Many对称的关系吗?

将函数的值作为输入参数返回给另一个