From eca016bb1c455a7a971e931b41082ce26e535dcb Mon Sep 17 00:00:00 2001 From: Masayoshi Mizutani Date: Sun, 24 Nov 2024 11:01:56 +0900 Subject: [PATCH 1/2] working --- clone.go | 5 +++++ clone_test.go | 14 ++++++++++++++ masq_test.go | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/clone.go b/clone.go index 08237fa..ba51fdf 100644 --- a/clone.go +++ b/clone.go @@ -58,6 +58,7 @@ func (x *masq) clone(ctx context.Context, fieldName string, src reflect.Value, t for i := 0; i < t.NumField(); i++ { f := t.Field(i) + println("f.Name", f.Name) srcValue := src.Field(i) dstValue := dst.Elem().Field(i) @@ -82,6 +83,10 @@ func (x *masq) clone(ctx context.Context, fieldName string, src reflect.Value, t } srcValue = reflect.NewAt(srcValue.Type(), unsafe.Pointer(srcValue.UnsafeAddr())).Elem() + } else if srcValue.Kind() == reflect.Func { + println("func!") + dstValue.Set(srcValue) + continue } tagValue := f.Tag.Get(x.tagKey) diff --git a/clone_test.go b/clone_test.go index 1658d40..7695a73 100644 --- a/clone_test.go +++ b/clone_test.go @@ -343,3 +343,17 @@ func TestCircularReference(t *testing.T) { newData := c.Redact(data).(*myStruct) gt.V(t, newData.Child.Child.Str).Equal("[REDACTED]") } + +func TestCloneJsonUnmarshalTypeError(t *testing.T) { + var s string + src := json.Unmarshal([]byte(`["foo"]`), &s).(*json.UnmarshalTypeError) + dst := masq.NewMasq().Redact(src).(*json.UnmarshalTypeError) + gt.Equal(t, dst, src) +} + +func TestCloneFunc(t *testing.T) { + type myFunc func() string + src := myFunc(func() string { return "blue" }) + dst := masq.NewMasq().Redact(src).(myFunc) + gt.Equal(t, dst(), "blue") +} diff --git a/masq_test.go b/masq_test.go index ab3f201..d3bbf3a 100644 --- a/masq_test.go +++ b/masq_test.go @@ -1,7 +1,10 @@ package masq_test import ( + "encoding/json" "os" + "reflect" + "testing" "log/slog" @@ -25,3 +28,19 @@ func Example() { logger.Info("hello", slog.Any("user", u)) } + +func TestJsonUnmarshalTypeError(t *testing.T) { + // It should not panic + logger := slog.New( + slog.NewJSONHandler( + os.Stdout, + &slog.HandlerOptions{ + ReplaceAttr: masq.New(masq.WithAllowedType(reflect.TypeOf(json.UnmarshalTypeError{}))), + }, + ), + ) + var s string + err := json.Unmarshal([]byte(`["foo"]`), &s) + slog.Info("error", "err", err) + logger.Info("error", "err", err) +} From 403f373c1b57215a82a4c94a75192616ff78d303 Mon Sep 17 00:00:00 2001 From: Masayoshi Mizutani Date: Mon, 9 Dec 2024 10:44:16 +0900 Subject: [PATCH 2/2] ignore reflect.rtype --- clone.go | 15 ++++++++++----- clone_test.go | 18 +++++++++++------- masq_test.go | 19 ------------------- 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/clone.go b/clone.go index ba51fdf..c516afe 100644 --- a/clone.go +++ b/clone.go @@ -12,6 +12,13 @@ const ( maxDepth = 32 ) +var ( + // ignoreTypes is a map of types that should not be redacted. It lists types that can not be copied. For example, reflect.Type is a pointer to a struct and copying it causes panic. Especially, reflect.rtype is unexported type. Then, the ignoreTypes is list of string of type name. + ignoreTypes = map[string]struct{}{ + "*reflect.rtype": {}, + } +) + func (x *masq) clone(ctx context.Context, fieldName string, src reflect.Value, tag string) reflect.Value { if v, ok := ctx.Value(ctxKeyDepth{}).(int); !ok { ctx = context.WithValue(ctx, ctxKeyDepth{}, 0) @@ -26,6 +33,9 @@ func (x *masq) clone(ctx context.Context, fieldName string, src reflect.Value, t if _, ok := x.allowedTypes[src.Type()]; ok { return src } + if _, ok := ignoreTypes[src.Type().String()]; ok { + return src + } if src.Kind() == reflect.Ptr && src.IsNil() { return reflect.New(src.Type()).Elem() @@ -58,7 +68,6 @@ func (x *masq) clone(ctx context.Context, fieldName string, src reflect.Value, t for i := 0; i < t.NumField(); i++ { f := t.Field(i) - println("f.Name", f.Name) srcValue := src.Field(i) dstValue := dst.Elem().Field(i) @@ -83,10 +92,6 @@ func (x *masq) clone(ctx context.Context, fieldName string, src reflect.Value, t } srcValue = reflect.NewAt(srcValue.Type(), unsafe.Pointer(srcValue.UnsafeAddr())).Elem() - } else if srcValue.Kind() == reflect.Func { - println("func!") - dstValue.Set(srcValue) - continue } tagValue := f.Tag.Get(x.tagKey) diff --git a/clone_test.go b/clone_test.go index 7695a73..b83de00 100644 --- a/clone_test.go +++ b/clone_test.go @@ -344,16 +344,20 @@ func TestCircularReference(t *testing.T) { gt.V(t, newData.Child.Child.Str).Equal("[REDACTED]") } -func TestCloneJsonUnmarshalTypeError(t *testing.T) { - var s string - src := json.Unmarshal([]byte(`["foo"]`), &s).(*json.UnmarshalTypeError) - dst := masq.NewMasq().Redact(src).(*json.UnmarshalTypeError) - gt.Equal(t, dst, src) -} - func TestCloneFunc(t *testing.T) { type myFunc func() string src := myFunc(func() string { return "blue" }) dst := masq.NewMasq().Redact(src).(myFunc) gt.Equal(t, dst(), "blue") } + +func TestUnmarshalTypeError(t *testing.T) { + var buf bytes.Buffer + logger := slog.New(slog.NewJSONHandler(&buf, &slog.HandlerOptions{ + ReplaceAttr: masq.New(), + })) + var s string + err := json.Unmarshal([]byte(`["foo"]`), &s) + logger.Info("error", slog.Any("err", err)) + gt.S(t, buf.String()).Contains("error") +} diff --git a/masq_test.go b/masq_test.go index d3bbf3a..ab3f201 100644 --- a/masq_test.go +++ b/masq_test.go @@ -1,10 +1,7 @@ package masq_test import ( - "encoding/json" "os" - "reflect" - "testing" "log/slog" @@ -28,19 +25,3 @@ func Example() { logger.Info("hello", slog.Any("user", u)) } - -func TestJsonUnmarshalTypeError(t *testing.T) { - // It should not panic - logger := slog.New( - slog.NewJSONHandler( - os.Stdout, - &slog.HandlerOptions{ - ReplaceAttr: masq.New(masq.WithAllowedType(reflect.TypeOf(json.UnmarshalTypeError{}))), - }, - ), - ) - var s string - err := json.Unmarshal([]byte(`["foo"]`), &s) - slog.Info("error", "err", err) - logger.Info("error", "err", err) -}