Эх сурвалжийг харах

fix time, duration, slice types on logx.Field (#1868)

* chore: refine tests

* fix #1866
Kevin Wan 3 жил өмнө
parent
commit
a36d58aac9
2 өөрчлөгдсөн 124 нэмэгдсэн , 0 устгасан
  1. 28 0
      core/logx/logs.go
  2. 96 0
      core/logx/logs_test.go

+ 28 - 0
core/logx/logs.go

@@ -113,8 +113,36 @@ func Errorw(msg string, fields ...LogField) {
 // Field returns a LogField for the given key and value.
 func Field(key string, value interface{}) LogField {
 	switch val := value.(type) {
+	case error:
+		return LogField{Key: key, Value: val.Error()}
+	case []error:
+		var errs []string
+		for _, err := range val {
+			errs = append(errs, err.Error())
+		}
+		return LogField{Key: key, Value: errs}
 	case time.Duration:
 		return LogField{Key: key, Value: fmt.Sprint(val)}
+	case []time.Duration:
+		var durs []string
+		for _, dur := range val {
+			durs = append(durs, fmt.Sprint(dur))
+		}
+		return LogField{Key: key, Value: durs}
+	case []time.Time:
+		var times []string
+		for _, t := range val {
+			times = append(times, fmt.Sprint(t))
+		}
+		return LogField{Key: key, Value: times}
+	case fmt.Stringer:
+		return LogField{Key: key, Value: val.String()}
+	case []fmt.Stringer:
+		var strs []string
+		for _, str := range val {
+			strs = append(strs, str.String())
+		}
+		return LogField{Key: key, Value: strs}
 	default:
 		return LogField{Key: key, Value: val}
 	}

+ 96 - 0
core/logx/logs_test.go

@@ -7,6 +7,7 @@ import (
 	"io/ioutil"
 	"log"
 	"os"
+	"reflect"
 	"runtime"
 	"strings"
 	"sync"
@@ -92,6 +93,86 @@ func (mw *mockWriter) String() string {
 	return mw.builder.String()
 }
 
+func TestField(t *testing.T) {
+	tests := []struct {
+		name string
+		f    LogField
+		want map[string]interface{}
+	}{
+		{
+			name: "error",
+			f:    Field("foo", errors.New("bar")),
+			want: map[string]interface{}{
+				"foo": "bar",
+			},
+		},
+		{
+			name: "errors",
+			f:    Field("foo", []error{errors.New("bar"), errors.New("baz")}),
+			want: map[string]interface{}{
+				"foo": []interface{}{"bar", "baz"},
+			},
+		},
+		{
+			name: "strings",
+			f:    Field("foo", []string{"bar", "baz"}),
+			want: map[string]interface{}{
+				"foo": []interface{}{"bar", "baz"},
+			},
+		},
+		{
+			name: "duration",
+			f:    Field("foo", time.Second),
+			want: map[string]interface{}{
+				"foo": "1s",
+			},
+		},
+		{
+			name: "durations",
+			f:    Field("foo", []time.Duration{time.Second, 2 * time.Second}),
+			want: map[string]interface{}{
+				"foo": []interface{}{"1s", "2s"},
+			},
+		},
+		{
+			name: "times",
+			f: Field("foo", []time.Time{
+				time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC),
+				time.Date(2020, time.January, 2, 0, 0, 0, 0, time.UTC),
+			}),
+			want: map[string]interface{}{
+				"foo": []interface{}{"2020-01-01 00:00:00 +0000 UTC", "2020-01-02 00:00:00 +0000 UTC"},
+			},
+		},
+		{
+			name: "stringer",
+			f:    Field("foo", ValStringer{val: "bar"}),
+			want: map[string]interface{}{
+				"foo": "bar",
+			},
+		},
+		{
+			name: "stringers",
+			f:    Field("foo", []fmt.Stringer{ValStringer{val: "bar"}, ValStringer{val: "baz"}}),
+			want: map[string]interface{}{
+				"foo": []interface{}{"bar", "baz"},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		test := test
+		t.Run(test.name, func(t *testing.T) {
+			w := new(mockWriter)
+			old := writer.Swap(w)
+			defer writer.Store(old)
+
+			Infow("foo", test.f)
+			validateFields(t, w.String(), test.want)
+		})
+	}
+}
+
 func TestFileLineFileMode(t *testing.T) {
 	w := new(mockWriter)
 	old := writer.Swap(w)
@@ -675,3 +756,18 @@ type ValStringer struct {
 func (v ValStringer) String() string {
 	return v.val
 }
+
+func validateFields(t *testing.T, content string, fields map[string]interface{}) {
+	var m map[string]interface{}
+	if err := json.Unmarshal([]byte(content), &m); err != nil {
+		t.Error(err)
+	}
+
+	for k, v := range fields {
+		if reflect.TypeOf(v).Kind() == reflect.Slice {
+			assert.EqualValues(t, v, m[k])
+		} else {
+			assert.Equal(t, v, m[k], content)
+		}
+	}
+}