2
0

decode.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Package implements the decoding of logfmt key-value pairs.
  2. //
  3. // Example logfmt message:
  4. //
  5. // foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf
  6. //
  7. // Example result in JSON:
  8. //
  9. // { "foo": "bar", "a": 14, "baz": "hello kitty", "cool%story": "bro", "f": true, "%^asdf": true }
  10. //
  11. // EBNFish:
  12. //
  13. // ident_byte = any byte greater than ' ', excluding '=' and '"'
  14. // string_byte = any byte excluding '"' and '\'
  15. // garbage = !ident_byte
  16. // ident = ident_byte, { ident byte }
  17. // key = ident
  18. // value = ident | '"', { string_byte | '\', '"' }, '"'
  19. // pair = key, '=', value | key, '=' | key
  20. // message = { garbage, pair }, garbage
  21. package logfmt
  22. import (
  23. "reflect"
  24. "strconv"
  25. "strings"
  26. "time"
  27. )
  28. // Handler is the interface implemented by objects that accept logfmt
  29. // key-value pairs. HandleLogfmt must copy the logfmt data if it
  30. // wishes to retain the data after returning.
  31. type Handler interface {
  32. HandleLogfmt(key, val []byte) error
  33. }
  34. // The HandlerFunc type is an adapter to allow the use of ordinary functions as
  35. // logfmt handlers. If f is a function with the appropriate signature,
  36. // HandlerFunc(f) is a Handler object that calls f.
  37. type HandlerFunc func(key, val []byte) error
  38. func (f HandlerFunc) HandleLogfmt(key, val []byte) error {
  39. return f(key, val)
  40. }
  41. // Unmarshal parses the logfmt encoding data and stores the result in the value
  42. // pointed to by v. If v is an Handler, HandleLogfmt will be called for each
  43. // key-value pair.
  44. //
  45. // If v is not a Handler, it will pass v to NewStructHandler and use the
  46. // returned StructHandler for decoding.
  47. func Unmarshal(data []byte, v interface{}) (err error) {
  48. h, ok := v.(Handler)
  49. if !ok {
  50. h, err = NewStructHandler(v)
  51. if err != nil {
  52. return err
  53. }
  54. }
  55. return gotoScanner(data, h)
  56. }
  57. // StructHandler unmarshals logfmt into a struct. It matches incoming keys to
  58. // the the struct's fields (either the struct field name or its tag, preferring
  59. // an exact match but also accepting a case-insensitive match.
  60. //
  61. // Field types supported by StructHandler are:
  62. //
  63. // all numeric types (e.g. float32, int, etc.)
  64. // []byte
  65. // string
  66. // bool - true if key is present, false otherwise (the value is ignored).
  67. // time.Duration - uses time.ParseDuration
  68. //
  69. // If a field is a pointer to an above type, and a matching key is not present
  70. // in the logfmt data, the pointer will be untouched.
  71. //
  72. // If v is not a pointer to an Handler or struct, Unmarshal will return an
  73. // error.
  74. type StructHandler struct {
  75. rv reflect.Value
  76. }
  77. func NewStructHandler(v interface{}) (Handler, error) {
  78. rv := reflect.ValueOf(v)
  79. if rv.Kind() != reflect.Ptr || rv.IsNil() {
  80. return nil, &InvalidUnmarshalError{reflect.TypeOf(v)}
  81. }
  82. return &StructHandler{rv: rv}, nil
  83. }
  84. func (h *StructHandler) HandleLogfmt(key, val []byte) error {
  85. el := h.rv.Elem()
  86. skey := string(key)
  87. for i := 0; i < el.NumField(); i++ {
  88. fv := el.Field(i)
  89. ft := el.Type().Field(i)
  90. switch {
  91. case ft.Name == skey:
  92. case ft.Tag.Get("logfmt") == skey:
  93. case strings.EqualFold(ft.Name, skey):
  94. default:
  95. continue
  96. }
  97. if fv.Kind() == reflect.Ptr {
  98. if fv.IsNil() {
  99. t := fv.Type().Elem()
  100. v := reflect.New(t)
  101. fv.Set(v)
  102. fv = v
  103. }
  104. fv = fv.Elem()
  105. }
  106. switch fv.Interface().(type) {
  107. case time.Duration:
  108. d, err := time.ParseDuration(string(val))
  109. if err != nil {
  110. return &UnmarshalTypeError{string(val), fv.Type()}
  111. }
  112. fv.Set(reflect.ValueOf(d))
  113. case string:
  114. fv.SetString(string(val))
  115. case []byte:
  116. b := make([]byte, len(val))
  117. copy(b, val)
  118. fv.SetBytes(b)
  119. case bool:
  120. fv.SetBool(true)
  121. default:
  122. switch {
  123. case reflect.Int <= fv.Kind() && fv.Kind() <= reflect.Int64:
  124. v, err := strconv.ParseInt(string(val), 10, 64)
  125. if err != nil {
  126. return err
  127. }
  128. fv.SetInt(v)
  129. case reflect.Uint32 <= fv.Kind() && fv.Kind() <= reflect.Uint64:
  130. v, err := strconv.ParseUint(string(val), 10, 64)
  131. if err != nil {
  132. return err
  133. }
  134. fv.SetUint(v)
  135. case reflect.Float32 <= fv.Kind() && fv.Kind() <= reflect.Float64:
  136. v, err := strconv.ParseFloat(string(val), 10)
  137. if err != nil {
  138. return err
  139. }
  140. fv.SetFloat(v)
  141. default:
  142. return &UnmarshalTypeError{string(val), fv.Type()}
  143. }
  144. }
  145. }
  146. return nil
  147. }
  148. // An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
  149. // (The argument to Unmarshal must be a non-nil pointer.)
  150. type InvalidUnmarshalError struct {
  151. Type reflect.Type
  152. }
  153. func (e *InvalidUnmarshalError) Error() string {
  154. if e.Type == nil {
  155. return "logfmt: Unmarshal(nil)"
  156. }
  157. if e.Type.Kind() != reflect.Ptr {
  158. return "logfmt: Unmarshal(non-pointer " + e.Type.String() + ")"
  159. }
  160. return "logfmt: Unmarshal(nil " + e.Type.String() + ")"
  161. }
  162. // An UnmarshalTypeError describes a logfmt value that was
  163. // not appropriate for a value of a specific Go type.
  164. type UnmarshalTypeError struct {
  165. Value string // the logfmt value
  166. Type reflect.Type // type of Go value it could not be assigned to
  167. }
  168. func (e *UnmarshalTypeError) Error() string {
  169. return "logfmt: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
  170. }