Trim log source field to basename of file (#273)

This makes logs more readable and avoids leaking paths.

Before:
```
time=2023-03-22T16:38:30.238+01:00 level=INFO source=/Users/pieter.noordhuis/dev/bricks/bundle/phases/phase.go:30 msg="Phase: initialize"
time=2023-03-22T16:38:31.303+01:00 level=INFO source=/Users/pieter.noordhuis/dev/bricks/bundle/phases/phase.go:30 msg="Phase: build"
time=2023-03-22T16:38:31.303+01:00 level=INFO source=/Users/pieter.noordhuis/dev/bricks/bundle/phases/phase.go:30 msg="Phase: deploy"
```

After:
```
time=2023-03-22T17:02:47.290+01:00 level=INFO source=phase.go:30 msg="Phase: initialize"
time=2023-03-22T17:02:48.171+01:00 level=INFO source=phase.go:30 msg="Phase: build"
time=2023-03-22T17:02:48.171+01:00 level=INFO source=phase.go:30 msg="Phase: deploy"
```
This commit is contained in:
Pieter Noordhuis 2023-03-23 08:56:39 +01:00 committed by GitHub
parent edd8630f71
commit 1b47dd3af7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 1 deletions

View File

@ -21,7 +21,10 @@ func initializeLogger(ctx context.Context, cmd *cobra.Command) (context.Context,
opts := slog.HandlerOptions{}
opts.Level = logLevel.Level()
opts.AddSource = true
opts.ReplaceAttr = log.ReplaceLevelAttr
opts.ReplaceAttr = log.ReplaceAttrFunctions{
log.ReplaceLevelAttr,
log.ReplaceSourceAttr,
}.ReplaceAttr
// Open the underlying log file if the user configured an actual file to log to.
err := logFile.Open()

18
libs/log/replace_attr.go Normal file
View File

@ -0,0 +1,18 @@
package log
import "golang.org/x/exp/slog"
type ReplaceAttrFunction func(groups []string, a slog.Attr) slog.Attr
// ReplaceAttrFunctions enables grouping functions that replace attributes
// from a [slog.Handler]. Useful when multiple attributes need replacing.
type ReplaceAttrFunctions []ReplaceAttrFunction
// ReplaceAttr can be used as a value to pass to a handler to combine
// multiple functions to replace attributes.
func (fns ReplaceAttrFunctions) ReplaceAttr(groups []string, a slog.Attr) slog.Attr {
for _, fn := range fns {
a = fn(groups, a)
}
return a
}

View File

@ -0,0 +1,32 @@
package log
import (
"testing"
"github.com/stretchr/testify/assert"
"golang.org/x/exp/slog"
)
func testReplaceA(groups []string, a slog.Attr) slog.Attr {
if a.Key == "foo" {
return slog.Int("foo", int(a.Value.Int64())+1)
}
return a
}
func TestReplaceAttrGroup(t *testing.T) {
var foo, bar, out slog.Attr
fn := ReplaceAttrFunctions{
testReplaceA,
testReplaceA,
}
foo = slog.Int("foo", 0)
out = fn.ReplaceAttr([]string{}, foo)
assert.EqualValues(t, 2, out.Value.Int64())
bar = slog.Int("bar", 0)
out = fn.ReplaceAttr([]string{}, bar)
assert.EqualValues(t, 0, out.Value.Int64())
}

17
libs/log/source.go Normal file
View File

@ -0,0 +1,17 @@
package log
import (
"path/filepath"
"golang.org/x/exp/slog"
)
// ReplaceSourceAttr rewrites the source attribute to include only the file's basename.
func ReplaceSourceAttr(groups []string, a slog.Attr) slog.Attr {
if a.Key != slog.SourceKey {
return a
}
a.Value = slog.StringValue(filepath.Base(a.Value.String()))
return a
}

20
libs/log/source_test.go Normal file
View File

@ -0,0 +1,20 @@
package log
import (
"testing"
"github.com/stretchr/testify/assert"
"golang.org/x/exp/slog"
)
func TestReplaceSourceAttrSourceKey(t *testing.T) {
attr := slog.String(slog.SourceKey, "bricks/bundle/phases/phase.go:30")
out := ReplaceSourceAttr([]string{}, attr)
assert.Equal(t, "phase.go:30", out.Value.String())
}
func TestReplaceSourceAttrOtherKey(t *testing.T) {
attr := slog.String("foo", "bar")
out := ReplaceSourceAttr([]string{}, attr)
assert.Equal(t, attr, out)
}