Open
Description
What version of Go are you using (go version
)?
Does this issue reproduce with the latest release?
yes
What did you do?
logger := slog.New(slog.NewJSONHandler(os.Stdout))
logger.LogAttrs(
context.Background(),
slog.LevelWarn,
"fancy message",
slog.Bool("msg", false),
slog.String("my attr", "something"),
)
What did you expect to see?
JSONHandler should be fixed by deduplicating those special keys (time, message, level, and source).
I use "source" as a key in a lot of my code right now, so I'd run into this problem.
Either
{
"time": "2023-04-01T04:27:46.0959443-06:00",
"level": "WARN",
"msg": "fancy message",
"my attr": "something"
}
Or
{
"time": "2023-04-01T04:27:46.0959443-06:00",
"level": "WARN",
"msg": "fancy message",
"msg.msg": false,
"my attr": "something"
}
Or
{
"time": "2023-04-01T04:27:46.0959443-06:00",
"level": "WARN",
"msg": "fancy message",
"fields": {
"msg": false,
"my attr": "something"
}
}
Or
{
"time": "2023-04-01T04:27:46.0959443-06:00",
"level": "WARN",
"msg": "fancy message",
"msg#01": false,
"my attr": "something"
}
What did you see instead?
Invalid json. It would break our log aggregation. Default/Builtin handlers should never create invalid output.
{
"time": "2023-04-01T04:27:46.0959443-06:00",
"level": "WARN",
"msg": "fancy message",
"msg": false,
"my attr": "something"
}
EDIT:
Hey all, I've created a logging handler middleware that will deduplicate attribute keys, before they go to the json logger.
Please check it out: https://github.com/veqryn/slog-dedup
go get github.com/veqryn/slog-dedup
package main
import (
"log/slog"
"os"
slogdedup "github.com/veqryn/slog-dedup"
)
func main() {
// OverwriteHandler
overwriter := slogdedup.NewOverwriteHandler(slog.NewJSONHandler(os.Stdout, nil), nil)
slog.SetDefault(slog.New(overwriter))
/*
{
"time": "2023-10-03T01:30:00Z",
"level": "INFO",
"msg": "this is the dedup overwrite handler",
"duplicated": "two"
}
*/
slog.Info("this is the dedup overwrite handler",
slog.String("duplicated", "zero"),
slog.String("duplicated", "one"),
slog.String("duplicated", "two"),
)
// IgnoreHandler
ignorer := slogdedup.NewIgnoreHandler(slog.NewJSONHandler(os.Stdout, nil), nil)
slog.SetDefault(slog.New(ignorer))
/*
{
"time": "2023-10-03T01:30:00Z",
"level": "INFO",
"msg": "this is the dedup ignore handler",
"duplicated": "zero"
}
*/
slog.Info("this is the dedup ignore handler",
slog.String("duplicated", "zero"),
slog.String("duplicated", "one"),
slog.String("duplicated", "two"),
)
// IncrementHandler
incrementer := slogdedup.NewIncrementHandler(slog.NewJSONHandler(os.Stdout, nil), nil)
slog.SetDefault(slog.New(incrementer))
/*
{
"time": "2023-10-03T01:30:00Z",
"level": "INFO",
"msg": "this is the dedup incrementer handler",
"duplicated": "zero",
"duplicated#01": "one",
"duplicated#02": "two"
}
*/
slog.Info("this is the dedup incrementer handler",
slog.String("duplicated", "zero"),
slog.String("duplicated", "one"),
slog.String("duplicated", "two"),
)
// AppendHandler
appender := slogdedup.NewAppendHandler(slog.NewJSONHandler(os.Stdout, nil), nil)
slog.SetDefault(slog.New(appender))
/*
{
"time": "2023-10-03T01:30:00Z",
"level": "INFO",
"msg": "this is the dedup appender handler",
"duplicated": [
"zero",
"one",
"two"
]
}
*/
slog.Info("this is the dedup appender handler",
slog.String("duplicated", "zero"),
slog.String("duplicated", "one"),
slog.String("duplicated", "two"),
)
}