From 3c83f3082692eaf4eabc3a2eb8105b53147901c5 Mon Sep 17 00:00:00 2001 From: andrey Date: Tue, 2 Jan 2024 15:38:42 +0300 Subject: [PATCH] update field slice --- .golangci.yml | 5 ++ bench_test.go | 1 - field/errors.go | 5 ++ field/field.go | 4 +- field/kind.go | 62 ++++++++++++++++++ field/value.go | 134 ++++++++++++++++++++++++++++++--------- logger_example_test.go | 138 ++++++++++++++++++++++++++++++++++++++++- logger_test.go | 1 - 8 files changed, 316 insertions(+), 34 deletions(-) create mode 100644 field/errors.go diff --git a/.golangci.yml b/.golangci.yml index 309ebc0..1491609 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -61,3 +61,8 @@ issues: - gomnd - ireturn - exhaustruct + - gochecknoglobals + - path: _example_test\.go + linters: + - lll + - goerr113 diff --git a/bench_test.go b/bench_test.go index 9d003f0..0ee96c1 100644 --- a/bench_test.go +++ b/bench_test.go @@ -12,7 +12,6 @@ import ( "gitoa.ru/go-4devs/log/field" ) -//nolint:gochecknoglobals var ( errExample = errors.New("fail") _messages = fakeMessages(1000) diff --git a/field/errors.go b/field/errors.go new file mode 100644 index 0000000..a00ddde --- /dev/null +++ b/field/errors.go @@ -0,0 +1,5 @@ +package field + +import "errors" + +var ErrUndefined = errors.New("indefined") diff --git a/field/field.go b/field/field.go index 4fedd86..d6ad541 100644 --- a/field/field.go +++ b/field/field.go @@ -85,7 +85,7 @@ func Uint8(key string, value uint8) Field { func Uint8s(key string, value ...uint8) Field { return Field{ Key: key, - Value: AnyValue(value), + Value: Uint8sValue(value), } } @@ -316,7 +316,7 @@ func Complex64(key string, value complex64) Field { func Complex64s(key string, value ...complex64) Field { return Field{ Key: key, - Value: AnyValue(value), + Value: Complex64sValue(value), } } diff --git a/field/kind.go b/field/kind.go index b4d4a33..4dbee69 100644 --- a/field/kind.go +++ b/field/kind.go @@ -1,5 +1,7 @@ package field +import "fmt" + //go:generate stringer -type=Kind -linecomment -output=kind_string.go type Kind int @@ -22,3 +24,63 @@ const ( KindGroup // group KindClosure // closure ) + +func (l Kind) MarshalJSON() ([]byte, error) { + return []byte("\"" + l.String() + "\""), nil +} + +func (l *Kind) UnmarshalJSON(in []byte) error { + return l.UnmarshalText(in[1 : len(in)-1]) +} + +func (l Kind) MarshalText() ([]byte, error) { + return []byte(l.String()), nil +} + +//nolint:gocyclo,cyclop +func (l *Kind) UnmarshalText(in []byte) error { + switch string(in) { + case KindAny.String(): + *l = KindAny + case KindArray.String(): + *l = KindArray + case KindNil.String(): + *l = KindNil + case KindString.String(): + *l = KindString + case KindBool.String(): + *l = KindBool + case KindInt64.String(): + *l = KindInt64 + case KindUint64.String(): + *l = KindUint64 + case KindFloat32.String(): + *l = KindFloat32 + case KindFloat64.String(): + *l = KindFloat64 + case KindComplex128.String(): + *l = KindComplex128 + case KindBinary.String(): + *l = KindBinary + case KindDuration.String(): + *l = KindDuration + case KindTime.String(): + *l = KindTime + case KindError.String(): + *l = KindError + case KindGroup.String(): + *l = KindGroup + case KindClosure.String(): + *l = KindClosure + } + + return fmt.Errorf("%w:filed(%v)", ErrUndefined, string(in)) +} + +func (l Kind) MarshalBinary() ([]byte, error) { + return []byte(l.String()), nil +} + +func (l *Kind) UnmarshalBinary(in []byte) error { + return l.UnmarshalText(in) +} diff --git a/field/value.go b/field/value.go index 6212c99..7681786 100644 --- a/field/value.go +++ b/field/value.go @@ -57,9 +57,14 @@ func BoolValue(v bool) Value { func BoolsValue(values []bool) Value { return Value{ Kind: KindArray, - any: Value{ - Kind: KindBool, - any: values, + num: uint64(len(values)), + any: func() []Value { + vals := make([]Value, len(values)) + for idx := range values { + vals[idx] = BoolValue(values[idx]) + } + + return vals }, } } @@ -79,12 +84,33 @@ func Uint64Value(v uint64) Value { } // Uint64sValue returns a Value for a []uint64. -func Uint64sValue(v []uint64) Value { +func Uint64sValue(values []uint64) Value { return Value{ Kind: KindArray, - any: Value{ - Kind: KindUint64, - any: v, + num: uint64(len(values)), + any: func() []Value { + vals := make([]Value, len(values)) + for idx := range values { + vals[idx] = Uint64Value(values[idx]) + } + + return vals + }, + } +} + +// Uint8sValue returns a Value for a []uint8. +func Uint8sValue(values []uint8) Value { + return Value{ + Kind: KindArray, + num: uint64(len(values)), + any: func() []Value { + vals := make([]Value, len(values)) + for idx := range values { + vals[idx] = Uint64Value(uint64(values[idx])) + } + + return vals }, } } @@ -107,9 +133,14 @@ func Int64Value(value int64) Value { func Int64sValue(value []int64) Value { return Value{ Kind: KindArray, - any: Value{ - Kind: KindInt64, - any: value, + num: uint64(len(value)), + any: func() []Value { + vals := make([]Value, len(value)) + for idx := range value { + vals[idx] = Int64Value(value[idx]) + } + + return vals }, } } @@ -129,12 +160,17 @@ func Float64Value(v float64) Value { } // Float64Value returns a Value for a floating-points number. -func Float64sValue(v []float64) Value { +func Float64sValue(values []float64) Value { return Value{ Kind: KindArray, - any: Value{ - Kind: KindFloat64, - any: v, + num: uint64(len(values)), + any: func() []Value { + vals := make([]Value, len(values)) + for idx := range values { + vals[idx] = Float64Value(values[idx]) + } + + return vals }, } } @@ -148,6 +184,22 @@ func Float64pValue(v *float64) Value { return Float64Value(*v) } +// Complex64sValue returns a Value for a []complex64. +func Complex64sValue(values []complex64) Value { + return Value{ + Kind: KindArray, + num: uint64(len(values)), + any: func() []Value { + vals := make([]Value, len(values)) + for idx := range values { + vals[idx] = Complex128Value(complex128(values[idx])) + } + + return vals + }, + } +} + // Complex128Value returns a Value for a complex128. func Complex128Value(v complex128) Value { return Value{ @@ -157,12 +209,17 @@ func Complex128Value(v complex128) Value { } // Complex128Value returns a Value for a []complex128. -func Complex128sValue(v []complex128) Value { +func Complex128sValue(values []complex128) Value { return Value{ Kind: KindArray, - any: Value{ - Kind: KindComplex128, - any: v, + num: uint64(len(values)), + any: func() []Value { + vals := make([]Value, len(values)) + for idx := range values { + vals[idx] = Complex128Value(values[idx]) + } + + return vals }, } } @@ -191,12 +248,17 @@ func TimepValue(v *time.Time) Value { } // TimesValue returns a Value for a []time.Time. -func TimesValue(v []time.Time) Value { +func TimesValue(values []time.Time) Value { return Value{ Kind: KindArray, - any: Value{ - Kind: KindTime, - any: v, + num: uint64(len(values)), + any: func() []Value { + vals := make([]Value, len(values)) + for idx := range values { + vals[idx] = TimeValue(values[idx]) + } + + return vals }, } } @@ -223,12 +285,17 @@ func DurationpValue(v *time.Duration) Value { } // DurationValue returns a Value for a *time.Duration. -func DurationsValue(v []time.Duration) Value { +func DurationsValue(values []time.Duration) Value { return Value{ Kind: KindArray, - any: Value{ - Kind: KindDuration, - any: v, + num: uint64(len(values)), + any: func() []Value { + vals := make([]Value, len(values)) + for idx := range values { + vals[idx] = DurationValue(values[idx]) + } + + return vals }, } } @@ -252,9 +319,14 @@ func ErrorValue(value error) Value { func ErrorsValue(value []error) Value { return Value{ Kind: KindArray, - any: Value{ - Kind: KindError, - any: value, + num: uint64(len(value)), + any: func() []Value { + vals := make([]Value, len(value)) + for idx := range value { + vals[idx] = ErrorValue(value[idx]) + } + + return vals }, } } @@ -314,6 +386,8 @@ func AnyValue(v any) Value { return Complex128sValue(value) case complex64: return Complex128Value(complex128(value)) + case []complex64: + return Complex64sValue(value) case time.Duration: return DurationValue(value) case *time.Duration: @@ -328,6 +402,8 @@ func AnyValue(v any) Value { return TimesValue(value) case uint8: return Uint64Value(uint64(value)) + case []uint8: + return Uint8sValue(value) case uint16: return Uint64Value(uint64(value)) case uint32: diff --git a/logger_example_test.go b/logger_example_test.go index d76ea8e..7f21118 100644 --- a/logger_example_test.go +++ b/logger_example_test.go @@ -2,10 +2,12 @@ package log_test import ( "context" + "errors" "fmt" "math" "os" "sync/atomic" + "time" "gitoa.ru/go-4devs/log" "gitoa.ru/go-4devs/log/entry" @@ -13,7 +15,6 @@ import ( "gitoa.ru/go-4devs/log/level" ) -//nolint:gochecknoglobals var ctx = context.Background() func setStdout() { @@ -68,6 +69,141 @@ type Obj struct { IsEnable bool } +var ( + obj = Obj{ + Name: "test obj", + } + + str = "test str" + boolsVal = true + intVal = int(math.MaxInt) + int8Val = int8(math.MaxInt8) + int16Val = int16(math.MaxInt16) + int32Val = int32(math.MaxInt32) + int64Val = int64(math.MaxInt64) + + uintVal = uint(math.MaxUint) + uint8Val = uint8(math.MaxUint8) + uint16Val = uint16(math.MaxInt16) + uint32Val = uint32(math.MaxInt32) + uint64Val = uint64(math.MaxInt64) + + float32Val = float32(math.MaxFloat32) + float64Val = float64(math.MaxFloat64) + + minute = time.Minute + timeVal = time.Unix(0, math.MaxInt32) +) + +func ExampleNew_anyField() { + logger := log.New(log.WithStdout(), log.WithJSONFormat()) + logger.InfoKV(ctx, "any info message", + field.Any("obj", Obj{Name: "obj name"}), + field.Any("obj", &obj), + field.Any("int", intVal), + field.Any("uint", uintVal), + field.Any("float", float64Val), + field.Any("time", timeVal), + field.Any("duration", time.Hour), + field.Any("error", errors.New("error")), + ) + // Output: + // {"msg":"any info message","obj":{"Name":"obj name","IsEnable":false},"obj":{"Name":"test obj","IsEnable":false},"int":9223372036854775807,"uint":18446744073709551615,"float":1.7976931348623157e+308,"time":"1970-01-01T03:00:02+03:00","duration":"1h0m0s","error":"error"} +} + +func ExampleNew_arrayField() { + logger := log.New(log.WithStdout(), log.WithJSONFormat()) + logger.InfoKV(ctx, "array info message", + field.Strings("strings", "string", str), + field.Bools("bools", true, false), + field.Ints("ints", 42, 24), + field.Int8s("int8s", 42, 24), + field.Int16s("int16s", 42, 24), + field.Int32s("int32s", 42, 24), + field.Int64s("int64s", 42, 24), + field.Uint8s("uint8s", uint8Val, 0), + field.Uint16s("uint16s", 42, 24), + field.Uint32s("uint32s", 42, 24), + field.Uint64s("uint64s", 42, 24), + field.Float32s("float32s", 42, 24), + field.Float64s("float64s", 42, 24), + field.Complex64s("complex64s", 42, 24), + field.Complex128s("complex128s", 42, 24), + field.Durations("durations", time.Minute, time.Second), + field.Times("times", time.Unix(0, 42), time.Unix(0, 24)), + field.Errors("errors", errors.New("error"), errors.New("error2")), + ) + // Output: + // {"msg":"array info message","strings":["string","test str"],"bools":[true,false],"ints":[42,24],"int8s":[42,24],"int16s":[42,24],"int32s":[42,24],"int64s":[42,24],"uint8s":[255,0],"uint16s":[42,24],"uint32s":[42,24],"uint64s":[42,24],"float32s":[42,24],"float64s":[42,24],"complex64s":["(42+0i)","(24+0i)"],"complex128s":["(42+0i)","(24+0i)"],"durations":["1m0s","1s"],"times":["1970-01-01T03:00:00+03:00","1970-01-01T03:00:00+03:00"],"errors":["error","error2"]} +} + +func ExampleNew_pointerField() { + logger := log.New(log.WithStdout(), log.WithJSONFormat()) + logger.InfoKV(ctx, "pointer info message", + field.Stringp("stringp", &str), + field.Stringp("stringp", nil), + field.Boolp("boolp", &boolsVal), + field.Boolp("boolp", nil), + field.Intp("intp", &intVal), + field.Intp("intp", nil), + field.Int8p("int8p", &int8Val), + field.Int8p("int8p", nil), + field.Int16p("int16p", &int16Val), + field.Int16p("int16p", nil), + field.Int32p("int32p", &int32Val), + field.Int32p("int32p", nil), + field.Int64p("int64p", &int64Val), + field.Int64p("int64p", nil), + field.Uintp("uintp", &uintVal), + field.Uintp("uintp", nil), + field.Uint8p("uint8p", &uint8Val), + field.Uint8p("uint8p", nil), + field.Uint16p("uint16p", &uint16Val), + field.Uint16p("uint16p", nil), + field.Uint32p("uint32p", &uint32Val), + field.Uint32p("uint32p", nil), + field.Uint64p("uint64p", &uint64Val), + field.Uint64p("uint64p", nil), + field.Float32p("float32p", &float32Val), + field.Float32p("float32p", nil), + field.Float64p("float64p", &float64Val), + field.Float64p("float64p", nil), + field.Durationp("durationp", &minute), + field.Durationp("durationp", nil), + field.Timep("timep", &timeVal), + field.Timep("timep", nil), + ) + // Output: + // {"msg":"pointer info message","stringp":"test str","stringp":null,"boolp":true,"boolp":null,"intp":9223372036854775807,"intp":null,"int8p":127,"int8p":null,"int16p":32767,"int16p":null,"int32p":2147483647,"int32p":null,"int64p":9223372036854775807,"int64p":null,"uintp":18446744073709551615,"uintp":null,"uint8p":255,"uint8p":null,"uint16p":32767,"uint16p":null,"uint32p":2147483647,"uint32p":null,"uint64p":9223372036854775807,"uint64p":null,"float32p":3.4028235e+38,"float32p":null,"float64p":1.7976931348623157e+308,"float64p":null,"durationp":"1m0s","durationp":null,"timep":"1970-01-01T03:00:02+03:00","timep":null} +} + +func ExampleNew_fields() { + logger := log.New(log.WithStdout(), log.WithJSONFormat()) + logger.InfoKV(ctx, "info message", + field.String("string", str), + field.Bool("bool", true), + field.Int("int", 42), + field.Int8("int8", 42), + field.Int16("int16", 42), + field.Int32("int32", 42), + field.Int64("int64", 42), + field.Uint8("uint8", uint8Val), + field.Uint16("uint16", 42), + field.Uint32("uint32", 42), + field.Uint64("uint64", 42), + field.Float32("float32", 42), + field.Float64("float64", 42), + field.Complex64("complex16", 42), + field.Complex128("complex128", 42), + field.Duration("duration", time.Minute), + field.Time("time", time.Unix(0, 42)), + field.FormatTime("format_time", time.UnixDate, timeVal), + field.Error("error", errors.New("error")), + ) + // Output: + // {"msg":"info message","string":"test str","bool":true,"int":42,"int8":42,"int16":42,"int32":42,"int64":42,"uint8":255,"uint16":42,"uint32":42,"uint64":42,"float32":42,"float64":42,"complex16":"(42+0i)","complex128":"(42+0i)","duration":"1m0s","time":"1970-01-01T03:00:00+03:00","format_time":"Thu Jan 1 03:00:02 MSK 1970","error":"error"} +} + func ExampleNew_jsonFormat() { logger := log.New(log.WithStdout(), log.WithJSONFormat()). With( diff --git a/logger_test.go b/logger_test.go index 08c99bd..cae645b 100644 --- a/logger_test.go +++ b/logger_test.go @@ -13,7 +13,6 @@ import ( "gitoa.ru/go-4devs/log/level" ) -//nolint:gochecknoglobals var requestID ctxKey = "requestID" func TestFields(t *testing.T) {