diff --git a/go.mod b/go.mod index 97b5c37..4e02496 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,16 @@ go 1.19 require ( github.com/ssgreg/journald v1.0.0 + github.com/stretchr/testify v1.8.0 go.uber.org/zap v1.24.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 ) require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/sys v0.1.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d2b09a2..116e1cd 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,11 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/ssgreg/journald v1.0.0 h1:0YmTDPJXxcWDPba12qNMdO6TxvfkFSYpFIJ31CwmLcU= github.com/ssgreg/journald v1.0.0/go.mod h1:RUckwmTM8ghGWPslq2+ZBZzbb9/2KgjzYZ4JEP+oRt0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= @@ -21,4 +24,8 @@ golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAb golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/zapjournald.go b/zapjournald.go index 168b220..2f5afc7 100644 --- a/zapjournald.go +++ b/zapjournald.go @@ -131,7 +131,6 @@ func getFieldValue(f zapcore.Field) interface{} { zapcore.ObjectMarshalerType, zapcore.InlineMarshalerType, zapcore.BinaryType, - zapcore.BoolType, zapcore.ByteStringType, zapcore.Complex128Type, zapcore.Complex64Type, @@ -153,13 +152,15 @@ func getFieldValue(f zapcore.Field) interface{} { zapcore.Uint32Type, zapcore.Uint16Type, zapcore.Uint8Type, - zapcore.UintptrType: + zapcore.UintptrType, + zapcore.BoolType: return f.Integer case zapcore.StringType: return f.String case zapcore.TimeType: if f.Interface != nil { - return f.Interface + // for example: zap.Time("k", time.Unix(100900, 0).In(time.UTC)) - will produce: "100900000000000 UTC" (result in nanoseconds) + return fmt.Sprintf("%d %v", f.Integer, f.Interface) } return f.Integer default: diff --git a/zapjournald_test.go b/zapjournald_test.go new file mode 100644 index 0000000..4c92119 --- /dev/null +++ b/zapjournald_test.go @@ -0,0 +1,94 @@ +package zapjournald + +import ( + "fmt" + "net" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// TestGetFieldValueWithStringFormatting testing unexported function getFieldValue and verifying that all zap field types have correct return values. +func TestGetFieldValueWithStringFormatting(t *testing.T) { + // Interface types. + addr := net.ParseIP("1.2.3.4") + name := usernameTestExample("phil") + ints := []int{5, 6} + + tests := []struct { + name string + field zap.Field + expect interface{} + }{ + {"ObjectMarshaler", zap.Object("k", name), "phil"}, + {"ArrayMarshaler", zap.Array("k", boolsTestExample([]bool{true})), "[true]"}, + {"Binary", zap.Binary("k", []byte("ab12")), "ab12"}, + {"Bool", zap.Bool("k", true), "1"}, + {"ByteString", zap.ByteString("k", []byte("ab12")), "ab12"}, + {"Complex128", zap.Complex128("k", 1+2i), "(1+2i)"}, + {"Complex64", zap.Complex64("k", 1+2i), "(1+2i)"}, + {"Duration", zap.Duration("k", 1), "1"}, + {"Float64", zap.Float64("k", 3.14), "4614253070214989087"}, + {"Float32", zap.Float32("k", 3.14), "1078523331"}, + {"Int64", zap.Int64("k", 1), "1"}, + {"Int32", zap.Int32("k", 1), "1"}, + {"Int16", zap.Int16("k", 1), "1"}, + {"Int8", zap.Int8("k", 1), "1"}, + {"String", zap.String("k", "foo"), "foo"}, + {"Time", zap.Time("k", time.Unix(0, 0).In(time.UTC)), "0 UTC"}, + {"TimeFull", zap.Time("k", time.Time{}), "0001-01-01 00:00:00 +0000 UTC"}, + {"Uint", zap.Uint("k", 1), "1"}, + {"Uint64", zap.Uint64("k", 1), "1"}, + {"Uint32", zap.Uint32("k", 1), "1"}, + {"Uint16", zap.Uint16("k", 1), "1"}, + {"Uint8", zap.Uint8("k", 1), "1"}, + {"Uintptr", zap.Uintptr("k", 0xa), "10"}, + {"Namespace", zap.Namespace("k"), ""}, + {"Stringer", zap.Stringer("k", addr), "1.2.3.4"}, + {"Reflect", zap.Reflect("k", ints), "[5 6]"}, + {"Error", zap.Error(fmt.Errorf("test")), "test"}, + {"Skip", zap.Skip(), ""}, + {"InlineMarshaller", zap.Inline(name), "phil"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fieldValue := valueToString(getFieldValue(tt.field)) + if !assert.Equal(t, tt.expect, fieldValue, "Unexpected output %s.", tt.name) { + t.Logf("type expected: %T\nGot: %T", tt.expect, fieldValue) + } + }) + } +} + +// usernameTestExample type, which are implements ObjectMarshaller interface. +type usernameTestExample string + +func (n usernameTestExample) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddString("username", string(n)) + return nil +} + +// boolsTestExample type, which are implements ArrayMarshaller interface. +type boolsTestExample []bool + +func (bs boolsTestExample) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range bs { + arr.AppendBool(bs[i]) + } + return nil +} + +func valueToString(value interface{}) string { + switch rv := value.(type) { + case string: + return rv + case []byte: + return string(rv) + default: + return fmt.Sprint(value) + } +}