# Migrating Prysm to Slog
```go!
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
slog.SetDefault(logger)
slog.Info("message")
slog.Error("message")
slog.Debug("message")
slog.Warn("message")
```
Contextual logging:
Instead of `logrus.WithFields`, contextual logs can be added in a key=>value style. A problem is it not type-safe and can mess up with unbalanced keys.
```go!
logger.Info(
"incoming request",
"method", "GET",
"time_taken_ms", 158,
"path", "/hello/world?q=search",
"status", 200,
"user_agent", "Googlebot/2.1 (+http://www.google.com/bot.html)",
)
```
Compared to logrus, however, we get strongly-typed fields with this usage:
```go!
logger.Info(
"incoming request",
slog.String("method", "GET"),
slog.Int("time_taken_ms", 158),
slog.String("path", "/hello/world?q=search"),
slog.Int("status", 200),
slog.String(
"user_agent",
"Googlebot/2.1 (+http://www.google.com/bot.html)",
),
)
```
We can also create grouped attributes:
```go!
logger.LogAttrs(
context.Background(),
slog.LevelInfo,
"image uploaded",
slog.Int("id", 23123),
slog.Group("properties",
slog.Int("width", 4000),
slog.Int("height", 3000),
slog.String("format", "jpeg"),
),
)
```
Child loggers can be helpful as part of a particular function, as groups can be attached to them. For example, we could have a group logger in trace mode or custom mode for different properties such as peers, attestation contents, etc.
```go=
child := logger.With(
slog.Group("program_info",
slog.Int("pid", os.Getpid()),
slog.String("go_version", buildInfo.GoVersion),
),
)
```
We can customize log levels, which would be excellent for p2p and for user experience:
```go=
var LevelNames = map[slog.Leveler]string{
LevelTrace: "TRACE",
LevelNotice: "NOTICE",
LevelFatal: "FATAL",
}
```
The source of a log can also be included in the log itself:
```go=
opts := slog.HandlerOptions{
AddSource: true,
Level: slog.LevelDebug,
}
"source":{"function":"main.main","file":"/home/ayo/dev/demo/slog/main.go","line":30}
```
We can also implement a `LogValue` interface on any of our types, including attestations, blocks, or any struct to customize how they will be logged, which is very helpful to minimize use of contextual logging.
```go
func (u *User) LogValue() slog.Value {
return slog.GroupValue(
slog.String("id", u.ID),
slog.String("name", u.FirstName+" "+u.LastName),
)
}
```
Handlers can be customized for nice colors and formatting in any way we prefer. We could offer users a nicer logging experience this way:
```go
func main() {
opts := PrettyHandlerOptions{
SlogOpts: slog.HandlerOptions{
Level: slog.LevelDebug,
},
}
handler := NewPrettyHandler(os.Stdout, opts)
logger := slog.New(handler)
slog.SetDefault(logger)
slog.Debug(
"executing database query",
slog.String("query", "SELECT * FROM users"),
)
slog.Info("image upload successful", slog.String("image_id", "39ud88"))
slog.Warn(
"storage is 90% full",
slog.String("available_space", "900.1 MB"),
)
slog.Error(
"An error occurred while processing the request",
slog.String("url", "https://example.com"),
)
}
```
With output:
![](https://hackmd.io/_uploads/HJrWLZYA3.png)
# Integration
Here are some things to note about integrating these changes
- [ ] Fluentd integration and correct JSON formatting (need to make sure that the slog prysm format with JSON matches the fluentd format)
- [ ] File output works correctly: need to make sure that outputting our Prysm slogs to a file work the same as with logrus
- [ ] Determine which types could implement the `LogValue` interface in Prysm to make them easy to log and avoid a major refactoring
- [ ] Ensure prefixes work
- [ ] Keep debug / info / warn / error the same in the first refactor, then introduce a custom p2p log level and change some of our logs to that
- [ ] Start with the validator client: change all logrus logs in there
- [ ] The webUI supports log streaming: ensure we can still do this