go 建议:将log/slog中的Value.MarshalJSON添加到代码片段中,

llmtgqce  于 4个月前  发布在  Go
关注(0)|答案(1)|浏览(36)

encoding/json 包将 slog.Value 作为 {} 进行编组。这意味着如果 slog.Value 出现在被记录的某个内容中,slog.JSONHandler(以及任何其他输出 JSON 且不特殊对待 slog.Value 的处理器)将丢失其信息。(参见 #62699 。)
要解决这个问题,我建议添加

package slog

func (v Value) MarshalJSON() ([]byte, error) {
    return json.Marshal(v.Any())
}
rur96b6h

rur96b6h1#

虽然这将正确处理切片中的 slog.Value,但不幸的是,它无法处理切片中的 slog.LogValuer
以使用 slog.LogValuer 在 slog 文档中隐藏秘密的示例为基础:

package main

import (
	"log/slog"
	"os"
)

// A token is a secret value that grants permissions.
type Token string

// LogValue implements slog.LogValuer.
// It avoids revealing the token.
func (Token) LogValue() slog.Value {
	return slog.StringValue("REDACTED_TOKEN")
}

// This example demonstrates a Value that replaces itself
// with an alternative representation to avoid revealing secrets.
func main() {
	t := Token("shhhh!")
	logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
	logger.Info("permission granted", "user", "Perry", "token", t)

	tokens := []Token{"keep it secret", "keep it safe"}
	logger.Info("permission revoked", "tokens", tokens)
}

Playground link: https://go.dev/play/p/FBcVYD0patm
我希望看到秘密保持秘密,但今天的设计在这些上下文中不尊重 slog.LogValuer,导致不幸的后果(我在实际应用程序代码中遇到了一个不太灾难性的版本)。
由于这种行为,我发现对于需要可靠序列化的自定义类型,实现 slog.LogValuer 实际上是不够的——您还需要实现 MarshalJSON。在某些情况下这是不幸的,而在其他情况下,由于某种原因不适合记录的规范 JSON 表示法已经存在,因此需要单独的类型或手动序列化。
我不反对这个提案,但我在想是否有一个更一般性的解决方案来解决这个问题。在我看来,理想的行为是在任何嵌套级别上,对于 slog -serialized JSON,LogValue() 优先于 MarshalJSON()。我不确定是否有简单的方法使类似的东西起作用。

相关问题