@@ -12,8 +12,19 @@ import (
12
12
"go.coder.com/slog"
13
13
)
14
14
15
+ // Reflector is implemented by a value passed to Field
16
+ // that would like to only use the reflection based
17
+ // converter for itself and ignore interfaces like error
18
+ // or fmt.Stringer.
19
+ // TODO add back ValueFunc
20
+ type Reflector interface {
21
+ LogWithReflect ()
22
+ }
23
+
15
24
// Reflect uses reflection to convert the slice of fields into a ordered
16
25
// map that uses only the primitive value types defined in this package.
26
+ // It uses interfaces like error and fmt.Stringer where appropriate.
27
+ // Have a type implement Reflector if you would like to force
17
28
func Reflect (fs []slog.Field ) Map {
18
29
var m Map
19
30
for _ , f := range fs {
@@ -39,6 +50,9 @@ func reflectValue(rv reflect.Value) Value {
39
50
40
51
typ := rv .Type ()
41
52
switch {
53
+ case implements (typ , (* Reflector )(nil )):
54
+ // Skip checking for any other interfaces as the value wants
55
+ //
42
56
case implements (typ , (* Value )(nil )):
43
57
v := rv .MethodByName ("isSlogCoreValue" ).Call (nil )
44
58
return v [0 ].Interface ().(Value )
@@ -109,35 +123,41 @@ func reflectValue(rv reflect.Value) Value {
109
123
m .sort ()
110
124
return m
111
125
case reflect .Struct :
112
- typ := rv .Type ()
113
-
114
- f := make (Map , 0 , typ .NumField ())
126
+ m := make (Map , 0 , typ .NumField ())
127
+ m = reflectStruct (m , rv , typ )
128
+ return m
129
+ default :
130
+ return String (fmt .Sprintf ("%v" , rv ))
131
+ }
132
+ }
115
133
116
- for i := 0 ; i < typ .NumField (); i ++ {
117
- ft := typ .Field (i )
118
- fv := rv .Field (i )
134
+ func reflectStruct (m Map , rv reflect.Value , typ reflect.Type ) Map {
135
+ for i := 0 ; i < typ .NumField (); i ++ {
136
+ ft := typ .Field (i )
137
+ fv := rv .Field (i )
119
138
120
- if ft .Tag .Get ("log" ) == "-" {
121
- continue
122
- }
123
- if implements (typ , (* proto .Message )(nil )) && strings .HasPrefix (ft .Name , "XXX_" ) {
124
- // Have to ignore XXX_ fields for protobuf messages.
125
- continue
126
- }
139
+ if ft .Tag .Get ("log" ) == "-" {
140
+ continue
141
+ }
142
+ if implements (typ , (* proto .Message )(nil )) && strings .HasPrefix (ft .Name , "XXX_" ) {
143
+ // Have to ignore XXX_ fields for protobuf messages.
144
+ continue
145
+ }
127
146
128
- v := reflectValue (fv )
129
- name := ft .Tag .Get ("log" )
130
- if name == "" {
131
- name = snakecase (ft .Name )
132
- }
133
- f = f .appendVal (name , v )
147
+ if ft .Anonymous {
148
+ m = reflectStruct (m , fv , ft .Type )
149
+ continue
150
+ }
134
151
152
+ v := reflectValue (fv )
153
+ name := ft .Tag .Get ("log" )
154
+ if name == "" {
155
+ name = snakecase (ft .Name )
135
156
}
157
+ m = m .appendVal (name , v )
136
158
137
- return f
138
- default :
139
- return String (fmt .Sprintf ("%v" , rv ))
140
159
}
160
+ return m
141
161
}
142
162
143
163
func snakecase (s string ) string {
0 commit comments