github.com/mundipagg/tracer-splunk-writer@v1.0.6/json/encoder/struct.go (about) 1 package encoder 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "reflect" 8 "strings" 9 "unsafe" 10 11 jsoniter "github.com/json-iterator/go" 12 ) 13 14 type Struct struct { 15 Type reflect.Type 16 Strategy func(string) string 17 } 18 19 func (changer *Struct) IsEmpty(ptr unsafe.Pointer) bool { 20 return false 21 } 22 23 func (changer *Struct) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) { 24 beforeBuffer := stream.Buffer() 25 defer func() { 26 err := recover() 27 if err != nil { 28 fmt.Fprintf(os.Stderr, "a error occurred while serialization of '%v', error: '%v'", changer.Type.Name(), err) 29 stream.SetBuffer(beforeBuffer) 30 } 31 }() 32 v := reflect.NewAt(changer.Type, ptr).Elem() 33 switch value := v.Interface().(type) { 34 case json.Marshaler: 35 valueJ, _ := value.MarshalJSON() 36 var valueM interface{} 37 _ = json.Unmarshal(valueJ, &valueM) 38 stream.WriteVal(valueM) 39 case error: 40 stream.WriteString(value.Error()) 41 default: 42 stream.WriteObjectStart() 43 numFields := v.NumField() 44 if numFields > 0 { 45 var i int 46 for i = 0; i < numFields; i++ { 47 fv := v.Field(i) 48 ft := changer.Type.Field(i) 49 if changer.writeField(ft, fv, stream, false) { 50 break 51 } 52 } 53 i++ 54 for ; i < numFields; i++ { 55 fv := v.Field(i) 56 ft := changer.Type.Field(i) 57 changer.writeField(ft, fv, stream, true) 58 } 59 } 60 stream.WriteObjectEnd() 61 } 62 } 63 64 func (changer *Struct) writeField(structField reflect.StructField, value reflect.Value, stream *jsoniter.Stream, needsComma bool) bool { 65 if !value.CanInterface() { 66 return false 67 } 68 69 tag := strings.TrimSpace(structField.Tag.Get("json")) 70 71 if len(tag) == 0 { 72 if needsComma { 73 stream.WriteMore() 74 } 75 stream.WriteObjectField(changer.Strategy(structField.Name)) 76 stream.WriteVal(value.Interface()) 77 78 } else { 79 pieces := strings.Split(tag, ",") 80 if len(pieces) > 1 { 81 if pieces[1] == "omitempty" { 82 isZero := func() (isZero bool) { 83 defer func() { 84 if recover() != nil { 85 isZero = false 86 } 87 }() 88 return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface()) 89 }() 90 isNil := func() (isNil bool) { 91 defer func() { 92 if recover() != nil { 93 isNil = false 94 } 95 }() 96 return value.IsNil() 97 }() 98 if isNil || isZero { 99 return false 100 } 101 } 102 } 103 104 if pieces[0] == "-" { 105 return false 106 } 107 108 if needsComma { 109 stream.WriteMore() 110 } 111 stream.WriteObjectField(changer.Strategy(pieces[0])) 112 stream.WriteVal(value.Interface()) 113 } 114 return true 115 }