diff --git a/map.go b/map.go index 636f4ee..cbf2991 100644 --- a/map.go +++ b/map.go @@ -2,6 +2,7 @@ package slog import ( "bytes" + "database/sql/driver" "encoding/json" "fmt" "reflect" @@ -70,6 +71,14 @@ func marshalList(rv reflect.Value) []byte { } func encode(v interface{}) []byte { + if vr, ok := v.(driver.Valuer); ok { + var err error + v, err = vr.Value() + if err != nil { + return encodeJSON(fmt.Sprintf("error calling Value: %v", err)) + } + } + switch v := v.(type) { case json.Marshaler: return encodeJSON(v) diff --git a/map_test.go b/map_test.go index fce13b5..c89adf0 100644 --- a/map_test.go +++ b/map_test.go @@ -62,12 +62,12 @@ func TestMap(t *testing.T) { { "msg": "wrap1", "fun": "cdr.dev/slog_test.TestMap.func2", - "loc": "`+mapTestFile+`:41" + "loc": "`+mapTestFile+`:41" }, { "msg": "wrap2", "fun": "cdr.dev/slog_test.TestMap.func2", - "loc": "`+mapTestFile+`:42" + "loc": "`+mapTestFile+`:42" }, "EOF" ], @@ -93,7 +93,7 @@ func TestMap(t *testing.T) { { "msg": "failed to marshal to JSON", "fun": "cdr.dev/slog.encodeJSON", - "loc": "`+mapTestFile+`:131" + "loc": "`+mapTestFile+`:140" }, "json: error calling MarshalJSON for type slog_test.complexJSON: json: unsupported type: complex128" ], diff --git a/sloggers/slogjson/slogjson_test.go b/sloggers/slogjson/slogjson_test.go index 79a46e7..cdbffee 100644 --- a/sloggers/slogjson/slogjson_test.go +++ b/sloggers/slogjson/slogjson_test.go @@ -3,6 +3,7 @@ package slogjson_test import ( "bytes" "context" + "database/sql" "fmt" "runtime" "testing" @@ -33,7 +34,33 @@ func TestMake(t *testing.T) { l.Error(ctx, "line1\n\nline2", slog.F("wowow", "me\nyou")) j := entryjson.Filter(b.String(), "ts") - exp := fmt.Sprintf(`{"level":"ERROR","msg":"line1\n\nline2","caller":"%v:33","func":"cdr.dev/slog/sloggers/slogjson_test.TestMake","logger_names":["named"],"trace":"%v","span":"%v","fields":{"wowow":"me\nyou"}} + exp := fmt.Sprintf(`{"level":"ERROR","msg":"line1\n\nline2","caller":"%v:34","func":"cdr.dev/slog/sloggers/slogjson_test.TestMake","logger_names":["named"],"trace":"%v","span":"%v","fields":{"wowow":"me\nyou"}} `, slogjsonTestFile, span.SpanContext().TraceID().String(), span.SpanContext().SpanID().String()) assert.Equal(t, "entry", exp, j) } + +func TestNoDriverValue(t *testing.T) { + t.Parallel() + + b := &bytes.Buffer{} + l := slog.Make(slogjson.Sink(b)) + l = l.Named("named") + validField := sql.NullString{ + String: "cat", + Valid: true, + } + invalidField := sql.NullString{ + String: "dog", + Valid: false, + } + validInt := sql.NullInt64{ + Int64: 42, + Valid: true, + } + l.Error(bg, "error!", slog.F("inval", invalidField), slog.F("val", validField), slog.F("int", validInt)) + + j := entryjson.Filter(b.String(), "ts") + exp := fmt.Sprintf(`{"level":"ERROR","msg":"error!","caller":"%v:60","func":"cdr.dev/slog/sloggers/slogjson_test.TestNoDriverValue","logger_names":["named"],"fields":{"inval":null,"val":"cat","int":42}} +`, slogjsonTestFile) + assert.Equal(t, "entry", exp, j) +}