charmbracelet / charmbracelet/log

Improve rendering of pointers to structs inside of slices and maps

Open
#186 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
3.4k
Forks
103
PR merge metrics
No merged PRs in 30d

Description

### Description

It would be great to be able to render pointers to structs contained inside slices and maps better.

This could be done either by an improved rendering by default or through some way to configure the way that attributes are rendered.

I wrote a simple helper to compare `devslog`, `log`, `slog` with text formatter and `slog` with `json` formatter:
```
go run telnesstech.com/cmd
[13:58:41] INFO devslog
S slice: 1 []*main.testingStruct
0: *main.testingStruct
Name: slice1
S ptr : *main.testingStruct
Name: test
M map : 1 map[string]*main.testingStruct
key: main.testingStruct
Name: test
2025/09/26 13:58:41 INFO charmbracelet/log slice=[0x140001260c0] ptr=&{Name:test} map=map[key:0x140001260e0]
time=2025-09-26T13:58:41.584+02:00 level=INFO msg=slog slice=[0x140001260c0] ptr=&{Name:test} map=map[key:0x140001260e0]
{"time":"2025-09-26T13:58:41.584822+02:00","level":"INFO","msg":"slog","slice":[{"Name":"slice1"}],"ptr":{"Name":"test"},"map":{"key":{"Name":"test"}}}
```

`devslog` does this by default which is very useful, especially as it mirrors what is likely to mirror the production-behavior when using `json` formatter. The relevant code from `devslogs` [starts around here](https://github.com/golang-cz/devslog/blob/master/devslog.go#L375-L386).

Another alternative would also be to have an option similar to slog's `ReplaceAttr` to allow the user themselves to configure how attributes are rendered, making this possible to implement yourself.

Code to print the demo above.
```go
package main

import (
"log/slog"
"os"

"github.com/charmbracelet/log"
"github.com/golang-cz/devslog"
)

func main() {
slice := []*testingStruct{{Name: "slice1"}}
ptr := &testingStruct{Name: "test"}
m := map[string]*testingStruct{"key": {Name: "test"}}

slog.New(devslog.NewHandler(os.Stdout, nil)).With("slice", slice, "ptr", ptr, "map", m).Info("devslog")
log.With("slice", slice, "ptr", ptr, "map", m).Info("charmbracelet/slog")
slog.New(slog.NewTextHandler(os.Stdout, nil)).With("slice", slice, "ptr", ptr, "map", m).Info("slog")
slog.New(slog.NewJSONHandler(os.Stdout, nil)).With("slice", slice, "ptr", ptr, "map", m).Info("slog")
}

type testingStruct struct {
Name string
}
```

Contributor guide

Open the contributing guide

Research direction

Use the provided Go demo as the reproduction and compare the current output for pointers to structs in slices and maps with the linked devslog.go rendering logic. The change is done when those nested values render structurally like the JSON formatter, or when an equivalent user configuration is available; no repository file or test is named in the issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
observability-sre
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.