diff --git a/internal/entryhuman/entry.go b/internal/entryhuman/entry.go index ef2d204..72a390d 100644 --- a/internal/entryhuman/entry.go +++ b/internal/entryhuman/entry.go @@ -64,6 +64,13 @@ func formatValue(v interface{}) string { return fmt.Sprintf("error calling Value: %v", err) } } + if _, ok := v.(slog.Map); ok { + byt, err := json.Marshal(v) + if err != nil { + panic(err) + } + return string(byt) + } if v == nil { return "" } diff --git a/internal/entryhuman/testdata/object.golden b/internal/entryhuman/testdata/object.golden index 855cb06..eda493c 100644 --- a/internal/entryhuman/testdata/object.golden +++ b/internal/entryhuman/testdata/object.golden @@ -1 +1 @@ -0001-01-01 00:00:00.000 [warn] obj="[{Name:obj1 Value:{foo:1 bar:2 dra:[98 108 97 104]}} {Name:obj2 Value:{foo:3 bar:4 dra:[98 108 97 104]}}]" map={"key1":"value1"} \ No newline at end of file +0001-01-01 00:00:00.000 [warn] obj={"obj1":"{foo:1 bar:2 dra:[98 108 97 104]}","obj2":"{foo:3 bar:4 dra:[98 108 97 104]}"} map={"key1":"value1"} \ No newline at end of file diff --git a/slog.go b/slog.go index adea6e2..b13db94 100644 --- a/slog.go +++ b/slog.go @@ -40,7 +40,14 @@ func (l Logger) Log(ctx context.Context, e SinkEntry) { return } - e.Fields = l.fields.append(e.Fields) + filteredFields := make(Map, 0, len(e.Fields)) + for _, fs := range l.fields.append(e.Fields) { + if fs.LevelFilter != nil && !fs.LevelFilter(l.level) { + continue + } + filteredFields = append(filteredFields, fs) + } + e.Fields = filteredFields e.LoggerNames = appendNames(l.names, e.LoggerNames...) for _, s := range l.sinks { @@ -227,8 +234,22 @@ func appendNames(names []string, names2 ...string) []string { // Field represents a log field. type Field struct { - Name string - Value interface{} + Name string `json:"name,omitempty"` + Value interface{} `json:"value,omitempty"` + + // LevelFilter, if set, instructs the logger to only process this field + // if it processing entries at the given level. + LevelFilter func(Level) bool `json:"-"` +} + +// DebugF is a convenience constructor for Field, with LevelFilter only +// allowing Debug level entries. +func DebugF(name string, value interface{}) Field { + f := F(name, value) + f.LevelFilter = func(l Level) bool { + return l == LevelDebug + } + return f } // F is a convenience constructor for Field. diff --git a/slog_test.go b/slog_test.go index b708b51..2c3f9fd 100644 --- a/slog_test.go +++ b/slog_test.go @@ -51,6 +51,23 @@ func TestLogger(t *testing.T) { assert.Equal(t, "sinks", s1, s2) }) + t.Run("levelFilter", func(t *testing.T) { + t.Parallel() + + s := &fakeSink{} + l := slog.Make(s) + + l.Info(bg, "wow", slog.Error(io.EOF), slog.DebugF("nosee", "me")) + + assert.Len(t, "entries", 1, s.entries) + assert.Len(t, "fields", 1, s.entries[0].Fields) + + l = l.Leveled(slog.LevelDebug) + l.Info(bg, "wow", slog.Error(io.EOF), slog.DebugF("nosee", "me")) + assert.Len(t, "entries", 2, s.entries) + assert.Len(t, "fields", 2, s.entries[1].Fields) + }) + t.Run("helper", func(t *testing.T) { t.Parallel()