github.com/seeker-insurance/kit@v0.0.13/jsonapi/runtime.go (about) 1 package jsonapi 2 3 import ( 4 "crypto/rand" 5 "fmt" 6 "io" 7 "reflect" 8 "time" 9 ) 10 11 type Event int 12 13 const ( 14 UnmarshalStart Event = iota 15 UnmarshalStop 16 MarshalStart 17 MarshalStop 18 ) 19 20 type Runtime struct { 21 ctx map[string]interface{} 22 } 23 24 type Events func(*Runtime, Event, string, time.Duration) 25 26 var Instrumentation Events 27 28 func NewRuntime() *Runtime { return &Runtime{make(map[string]interface{})} } 29 30 func (r *Runtime) WithValue(key string, value interface{}) *Runtime { 31 r.ctx[key] = value 32 33 return r 34 } 35 36 func (r *Runtime) Value(key string) interface{} { 37 return r.ctx[key] 38 } 39 40 func (r *Runtime) Instrument(key string) *Runtime { 41 return r.WithValue("instrument", key) 42 } 43 44 func (r *Runtime) shouldInstrument() bool { 45 return Instrumentation != nil 46 } 47 48 func (r *Runtime) UnmarshalPayload(reader io.Reader, model interface{}) error { 49 return r.instrumentCall(UnmarshalStart, UnmarshalStop, func() error { 50 return UnmarshalPayload(reader, model) 51 }) 52 } 53 54 func (r *Runtime) UnmarshalManyPayload(reader io.Reader, kind reflect.Type) (elems []interface{}, err error) { 55 r.instrumentCall(UnmarshalStart, UnmarshalStop, func() error { 56 elems, err = UnmarshalManyPayload(reader, kind) 57 return err 58 }) 59 60 return 61 } 62 63 func (r *Runtime) MarshalPayload(w io.Writer, model interface{}) error { 64 return r.instrumentCall(MarshalStart, MarshalStop, func() error { 65 return MarshalPayload(w, model) 66 }) 67 } 68 69 func (r *Runtime) instrumentCall(start Event, stop Event, c func() error) error { 70 if !r.shouldInstrument() { 71 return c() 72 } 73 74 instrumentationGUID, err := newUUID() 75 if err != nil { 76 return err 77 } 78 79 begin := time.Now() 80 Instrumentation(r, start, instrumentationGUID, time.Duration(0)) 81 82 if err := c(); err != nil { 83 return err 84 } 85 86 diff := time.Duration(time.Now().UnixNano() - begin.UnixNano()) 87 Instrumentation(r, stop, instrumentationGUID, diff) 88 89 return nil 90 } 91 92 // citation: http://play.golang.org/p/4FkNSiUDMg 93 func newUUID() (string, error) { 94 uuid := make([]byte, 16) 95 if _, err := io.ReadFull(rand.Reader, uuid); err != nil { 96 return "", err 97 } 98 // variant bits; see section 4.1.1 99 uuid[8] = uuid[8]&^0xc0 | 0x80 100 // version 4 (pseudo-random); see section 4.1.3 101 uuid[6] = uuid[6]&^0xf0 | 0x40 102 return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil 103 }